Design: Может ли WebAssembly.Instance перекомпилировать уже скомпилированный модуль?

Созданный на 27 окт. 2016  ·  94Комментарии  ·  Источник: WebAssembly/design

Скажем, у меня есть этот код:

let descriptor = /* ... */;
let memories = Array.apply(null, {length: 1024}).map(() => new WebAssembly.Memory(descriptor));
let instance = fetch('foo.wasm')
  .then(response => response.arrayBuffer())
  .then(buffer => WebAssembly.compile(buffer))
  .then(module => new WebAssembly.Instance(module, { memory: memories[1023] }));

Разрешено ли WebAssembly.Instance блокировать на значительный период времени. Может ли он, например, перекомпилировать WebAssembly.Module ?

В большинстве случаев я бы сказал нет, но что, если уже скомпилированному коду не очень нравится память, которую он получает? Скажем, потому что эта память является памятью медленного режима, а код был скомпилирован в предположении быстрого режима? возможно, memories[0] была памятью быстрого режима, но memories[1023] точно не будет.

А как насчет этого кода:

let instances = [0,1,2,3,4,5,6,7].map(v => fetch(`foo${v}.wasm`)
  .then(response => response.arrayBuffer())
  .then(buffer => WebAssembly.compile(buffer))
  .then(module => new WebAssembly.Instance(module)));

Могут ли эти вызовы WebAssembly.Instance вызывать перекомпиляцию?

Если предположить, что вышеизложенное имеет смысл, вот несколько связанных вопросов:

  • Нужна ли нам асинхронная функция, возвращающая обещание, которая может компилировать _и_ экземпляр? Я не говорю, что мы должны отказаться от каких-либо синхронных и асинхронных API, которые у нас уже есть, я предлагаю новый асинхронный API.
  • Как браузер показывает, что скомпилированный код в WebAssembly.Module быстр, а экземпляр WebAssembly.Memory подходит для такого быстрого кода? Прямо сейчас ответ, кажется, такой: «Попробуйте и посмотрите, заметите ли вы».
  • Как пользователь узнает, сколько экземпляров WebAssembly.Memory ему разрешено, прежде чем он получит медленный код (с учетом неявных, например, созданных во втором примере)?
JS embedding

Самый полезный комментарий

@kgryte Я должен был пояснить, что мой комментарий в первую очередь относится к браузеру как к контексту выполнения. Мы достигли поверхности API, которая по-прежнему предоставляет синхронные API. Браузеры могут налагать ограничение на размер модулей, передаваемых синхронным API (например, Chrome уже делает это), но это ограничение настраивается устройством для внедрения и не должно применяться к Node.

Все 94 Комментарий

Было бы неплохо, если бы WebAssembly.Instance иногда вызывали перекомпиляцию, таким образом неизменяемые глобальные переменные могли быть постоянно свернуты в сгенерированном коде. Например, Emscripten генерирует перемещаемый код, смещая все указатели на статические данные. Смещение передается как неизменяемая глобальная переменная при создании экземпляра модуля. Если WebAssembly.Instance можно перекомпилировать, он может специализировать сгенерированный код.

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

27 октября 2016 г., в 03:24, Майкл Бебенита [email protected]
написал:

Было бы неплохо, если бы WebAssembly.Instance иногда приводил к перекомпиляции,
таким образом неизменяемые глобальные переменные могут быть постоянно свернуты в сгенерированный
код. Например, Emscripten генерирует перемещаемый код, компенсируя все
указатели на статические данные. Смещение передается как неизменяемая глобальная переменная.
при создании экземпляра модуля. Если WebAssembly.Instance может перекомпилировать,
он мог бы специализировать сгенерированный код.

-
Вы получаете это, потому что подписаны на эту ветку.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/WebAssembly/design/issues/838#issuecomment -256522163,
или отключить поток
https://github.com/notifications/unsubscribe-auth/AEDOO9sJPgujK3k0f6P7laYV_zaJxES5ks5q3_1LgaJpZM4Kh1gM
.

Согласен, это будет в лучшем случае ненормативная записка.

В SM мы также в настоящее время намерены никогда не перекомпилировать экземпляр, чтобы была предсказуемая модель стоимости компиляции для разработчиков (в частности, чтобы разработчики могли использовать WebAssembly.compile и IDB для управления, когда они принимают попадание компиляции) . Перекомпиляция во время создания экземпляра из синхронного конструктора Instance , безусловно, нарушит эту модель затрат и может привести к серьезному мусору.

Но я действительно понимаю, что отдельная компиляция принципиально противоречит различным оптимизациям, которые можно было бы сделать, чтобы специализировать сгенерированный код под параметры окружающей среды. Объединение компиляции и создания экземпляров в одну асинхронную операцию имеет смысл и это то, что мы рассматривали в прошлом. Обратной стороной, конечно же, является то, что это препятствует явному кэшированию (нет Module ), поэтому разработчику приходится идти на неприятный компромисс. Некоторые варианты:

  • Impl может выполнять неявное кэширование с адресом содержимого (которое может включать параметры окружения в ключе), как мы делаем с asm.js в настоящее время в FF. Это было бы своего рода болью и имеет все проблемы предсказуемости / эвристики любого неявного кеша.
  • Мы могли бы создать новый способ (например, новый WebAssembly.Cache API, в котором вы передаете байт-код и параметры создания экземпляра и получаете обратно Promise<Instance> .

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

@ rossberg-chromium Кажется, я плохо объяснил свою цель: я не хочу спорить о том, что говорится в спецификации. Я пытаюсь указать на то, что кажется серьезным сюрпризом для разработчиков, скрывающимся под API. Разработчик не ожидает повторной компиляции результата .compile . Мне это кажется недостатком дизайна.

@lukewagner, даже при неявном или явном кешировании, у нас может быть та же проблема: сколько WebAssembly.Memory может быть создано в одном и том же адресном пространстве / источнике, является ограничением браузера. Мне нравится то, что вы предлагаете, но я думаю, что это ортогонально проблеме. Сообщите мне, если я неправильно понял то, что вы предлагаете.

Возможно, .compile и Module можно было бы дать Memory , а Instance имеет свойство .memory которое можно передать другим компиляциям / экземплярам. ?

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

@jfbastien При неявном / явном кэшировании, которому были предоставлены определенные параметры создания экземпляра (так Memory ), я не понимаю, как возникнет необходимость в перекомпиляции.

@jfbastien При неявном / явном кэшировании, которому были предоставлены определенные параметры создания экземпляра (так Memory ), я не понимаю, как возникнет необходимость в перекомпиляции.

Может быть:

  1. Создайте много Memory s.
  2. Скомпилируйте код с явной (медленной) проверкой границ, потому что было слишком много Memory ies.
  3. Кешируйте этот код.
  4. Покинуть страницу.
  5. Снова загрузить страницу.
  6. Выделите только один Memory , который получит быструю версию.
  7. Достать из кеша.
  8. Получите медленный код Instance .

На этом этапе я согласен, что вам не нужна _необходима_ перекомпиляция, но мы ведем себя немного глупо, проводя медленные проверки границ, когда нам это не нужно.

Как я уже сказал: мне нравится этот Cache API, который вы предлагаете, я думаю, он делает WebAssembly более удобным, но я думаю, что проблема все еще существует. 😢

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

  1. создать много Memory s
  2. запросить Instance из кеша, передав один из этих (медленных) Memory s
  3. медленный код компилируется, кэшируется и возвращается как Instance
  4. покинуть страницу
  5. загрузить страницу снова
  6. выделить только один Memory
  7. запросить Instance из кеша, передав быстрый Memory
  8. fast-code компилируется, кэшируется и возвращается как Instance

а после шага 8 все будущие загрузки страниц будут кэшироваться быстрым или медленным кодом.

@lukewagner Прежде всего, вы предлагаете

Для меня проблема заключается в следующем: одна из оптимизаций, которые нам всем фактически придется сделать по конкурентным причинам (проверка границ виртуальной памяти 4 ГБ, которую я просто назову хаком 4 ГБ), не может быть выполнена в текущей спецификации без ущерба для одна из этих вещей:

  • Вы можете обойтись без этого, если всегда выделяете 4 ГБ виртуальной памяти для любой памяти wasm. Это отпугнет людей от использования WebAssembly для небольших модулей, поскольку вы столкнетесь с ограничениями выделения виртуальной памяти, фрагментацией виртуальной памяти или другими проблемами, если выделите многие из них. Я также опасаюсь, что, если вы разрешите выделить много из них, вы снизите эффективность мер безопасности, таких как ASLR. Обратите внимание, что существующие API-интерфейсы не разделяют эту опасность, поскольку они фиксируют выделенную память и либо OOM, либо аварийно завершают работу, прежде чем позволят вам выделить гораздо больше, чем позволяет физическая память.
  • Вы можете уйти от этого, если разрешите перекомпиляцию, когда вы обнаружите несоответствие во время создания экземпляра (скомпилированный код требует взлома 4 ГБ, но в памяти нет этого распределения виртуальной памяти). Вы также можете обойтись без этого, если создание экземпляра переместит память в область 4 ГБ, но посмотрите предыдущий пункт. Так что, вероятно, в любое время, когда это произойдет, это будет ошибка P1 для браузера, который с ней столкнулся.

Я думаю, что это означает, что спецификация побудит поставщиков сходиться к тому, чтобы просто разрешить резервирование 4 ГБ в любое время, когда выделяется память wasm, или использовать оптимизацию кеша / ленивой компиляции / профиля для обнаружения этого.

Наконец, я не понимаю смысла делать что-либо из этого ненормативным. Это может быть нормативным, потому что мы могли бы сделать так, чтобы API исключил возможность того, что браузеру придется что-то компилировать, не зная, какой тип памяти у него будет. Я полагаю, что есть много способов сделать это. Например, создание экземпляра может вернуть обещание, и мы могли бы удалить отдельный этап компиляции. Это дало бы понять, что создание экземпляра - это шаг, который может занять некоторое время, что убедительно подразумевает для клиента, что это шаг, на котором выполняется компиляция. В таком API компилятор всегда знает, имеет ли память, для которой он компилирует, взлом 4 ГБ или нет.

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

@jfbastien в своем мотивирующем сценарии вы указали, что модуль был создан для предпочтения быстрой памяти. Я предполагаю, что вы в первую очередь преследуете возможность быстрой оптимизации памяти, когда этого требует конкретный модуль, и, возможно, вы не будете делать этого, когда модуль этого не хочет (ничего плохого, если в этом случае случайно наткнуться на это тоже , просто пытаюсь разделить приоритеты).

Если да, то как выглядят эти альтернативы кешированию или асинхронному экземпляру:

  1. Автору модуля требуется 4 ГБ в качестве минимальной / максимальной памяти.
  2. Вариант компиляции (по крайней мере, асинхронный, возможно, также синхронный), который создает экземпляр, принимающий только быструю память.

Что касается проблемы «взлома 4 ГБ» и несоответствия между памятью, использующей его, и кодом, который его ожидает, имеет ли смысл для компиляции внутренне испускать две версии кода? (Очевидно, это потребовало бы больше памяти, что печально, но, надеюсь, время компиляции не будет намного хуже, писатель может сгенерировать оба сразу?)

@mtrofin Я не думаю, что имеет смысл просить 4GiB, если вы не собираетесь его использовать. Виртуальное распределение отделено от цели использования, поэтому я думаю, что нам нужно разделить и то, и другое.

На 2: это все еще не очень полезно для разработчика: если они используют этот вариант, и он терпит неудачу, что тогда?

@kripken Я не думаю, что двойная компиляция - хорошая идея.

@kripken Я думаю, что это то, что мы сделали бы без какого-либо другого решения этой проблемы.

Я хочу, чтобы WebAssembly была отличной в случае случайного просмотра: вы рассказываете мне об интересной штуке, отправляете мне URL-адрес, я нажимаю на него, и я развлекаюсь в течение нескольких минут. Вот что делает Интернет крутым. Но это означает, что во многих компиляциях будет код, который не кэшируется, поэтому время компиляции будет играть большую роль в времени автономной работы пользователя. Итак, двойная компиляция меня огорчает.

@mtrofin

Автору модуля требуется 4 ГБ в качестве минимальной / максимальной памяти.

Это не совсем практично, поскольку многие устройства не имеют 4 ГБ физической памяти. Кроме того, это сложно указать.

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

Я не думаю, что нам нужны двойные компиляции.

@pizlonator До сих пор мы не рассматривали проекты, которые требовали различных режимов кодогенерации: мы просто всегда выделяли области 4 ГБ в 64-разрядной версии и наблюдали, как это успешно применяется для многих тысяч воспоминаний в Linux, OSX и Windows. У нас есть консервативная верхняя граница, чтобы предотвратить тривиальное полное исчерпание доступного адресного пространства, которого, как я ожидаю, будет достаточно для поддержки варианта использования многих малых библиотек. Итак, я думаю, что новое ограничение, которое мы здесь рассматриваем, заключается в том, что iOS имеет некоторые ограничения виртуального адресного пространства, которые могут уменьшить количество выделений 4 ГБ.

Итак, одно наблюдение состоит в том, что значительной части исключения проверки границ, допускаемого взломом 4 ГБ, можно избежать, просто имея небольшую защитную область в конце wasm-памяти. Наши первоначальные эксперименты показывают, что базовый анализ (ничего общего с циклами, просто устранение проверок загрузки / сохранения с одним и тем же базовым указателем) уже может устранить примерно половину проверок границ. И, наверное, могло бы стать лучше. Так что взлом на 4 ГБ был бы более скромным и менее необходимым ускорением.

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

@lukewagner

До сих пор мы не рассматривали проекты, которые требовали различных режимов кодогенерации: мы просто всегда выделяли области 4 ГБ в 64-разрядной версии и наблюдали, как это удается для многих тысяч воспоминаний в Linux, OSX и Windows. У нас есть консервативное общее количество, чтобы предотвратить тривиальное полное исчерпание доступного адресного пространства, которого, как я ожидаю, будет достаточно для поддержки варианта использования многих малых библиотек. Итак, я думаю, что новое ограничение, которое мы здесь рассматриваем, заключается в том, что iOS имеет некоторые ограничения виртуального адресного пространства, которые могут уменьшить количество выделений 4 ГБ.

Это не проблема iOS. Проблема в том, что если вы разрешаете много таких распределений, это создает угрозу безопасности, потому что каждое такое распределение снижает эффективность ASLR. Итак, я думаю, что виртуальная машина должна иметь возможность установить очень низкий предел для количества выделяемых ею пространств 4 ГБ, но это означает, что резервный путь не должен быть слишком дорогим (т.е. он не должен требовать перекомпиляции).

Какой у вас лимит на количество 4 ГБ памяти, которое вы бы выделили? Что вы будете делать, когда достигнете этого предела - полностью откажетесь или перекомпилируете при создании экземпляра?

Итак, одно наблюдение состоит в том, что значительной части исключения проверки границ, допускаемого взломом 4 ГБ, можно избежать, просто имея небольшую защитную область в конце wasm-памяти. Наши первоначальные эксперименты показывают, что базовый анализ (ничего общего с циклами, просто устранение проверок загрузки / сохранения с одним и тем же базовым указателем) уже может устранить примерно половину проверок границ. И, наверное, могло бы стать лучше. Так что взлом на 4 ГБ был бы более скромным и менее необходимым ускорением.

Я согласен с тем, что анализ позволяет нам исключить больше проверок, но взлом на 4 ГБ - это то, что вам нужно, если вам нужна максимальная производительность. Всем нужна максимальная производительность, и я думаю, было бы замечательно, если бы можно было получить максимальную производительность, не вызывая при этом проблем с безопасностью, проблем с ресурсами и неожиданной перекомпиляции.

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

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

Код, который использует взлом 4 ГБ, должен только закрепить регистр для базы памяти.

Так что это не лучшее решение.

Помимо раздражения, связанного со спецификацией и реализациями, каковы недостатки объединения компиляции и создания экземпляра в одно обещанное действие?

Проблема в том, что если вы разрешаете много таких распределений, это создает угрозу безопасности, потому что каждое такое
распределение снижает эффективность ASLR.

Я не эксперт по ASLR, но, iiuc, даже если у нас не было консервативной границы (то есть, если мы позволили вам продолжать выделение до тех пор, пока не произойдет сбой mmap потому что ядро ​​достигнет своего числа- address-range max), будет использована лишь небольшая часть всего 47-битного адресного пространства, поэтому размещение кода в этом 47-битном пространстве будет по-прежнему очень случайным. Размещение кода IIUC, ASLR также не является полностью случайным; ровно настолько, чтобы было трудно предсказать, где что-нибудь будет.

Какой у вас лимит на количество 4 ГБ памяти, которое вы бы выделили? Что вы делаете
когда вы достигнете этого предела - откажитесь полностью или перекомпилируйте при создании экземпляра?

Ну раз уж с asm.js дней всего 1000. Потом выделение памяти просто выкидывает. Возможно, нам придется это исправить, но даже со многими супермодульными приложениями (с множеством отдельных модулей wasm каждое), использующих один и тот же процесс, я не могу представить, что нам понадобится слишком много большего. Я думаю, что Memory отличается от простых старых ArrayBuffer s тем, что приложения, естественно, не хотят создавать тысячи.

Помимо раздражения, связанного со спецификациями и реализациями, каковы недостатки
объединения компиляции и создания экземпляра в одно обещанное действие?

Как я уже упоминал выше, добавление Promise<Instance> eval(bytecode, importObj) API - это нормально, но теперь это ставит разработчика в трудное положение, потому что теперь им приходится выбирать между повышением производительности на некоторых платформах и возможностью кэшировать свой скомпилированный код на все платформы. Похоже, нам нужно решение, которое интегрируется с кешированием, и это то, о чем я размышлял выше с явным API Cache .

Новая идея: что, если мы добавим асинхронную версию new Instance , скажем, WebAssembly.instantiate и, как и в случае с WebAssembly.compile , мы скажем, что все должны использовать асинхронную версию? Это то, что я рассматривал _ в любом случае_, поскольку создание экземпляра может занять несколько мс, если используется исправление. Затем мы говорим в спецификации, что движок может выполнять дорогостоящую работу либо в compile либо в instantiate (или ни в одном из них, если движок выполняет ленивую проверку / компиляцию!).

Это все еще оставляет вопрос, что делать, когда compile d Module хранится в IDB, но это просто сложный вопрос, когда есть несколько режимов кодогенерации _anyway_. Одна идея состоит в том, что Module , которые хранятся или извлекаются из IDB, удерживают дескриптор своей записи IDB и добавляют в эту запись новый скомпилированный код. Таким образом, запись IDB будет лениво накапливать одну или несколько скомпилированных версий своего модуля и сможет предоставить то, что требуется во время создания экземпляра.

Часть IDB - это немного больше работы, но она кажется довольно близкой к идеалу с точки зрения производительности. WDYT?

Я думаю, что добавление async instantiate имеет смысл, но я бы также добавил параметр Memory к compile . Если передать другую память в instantiate тогда вы можете перекомпилировать, иначе вы уже "связали" память при компиляции.

Я еще недостаточно подумал о кешировании, чтобы составить окончательное мнение.

@lukewagner

Я не эксперт по ASLR, но, iiuc, даже если у нас не было консервативной границы (то есть, если мы позволили вам продолжать выделение до тех пор, пока mmap не сработает, потому что ядро ​​достигнет максимального числа диапазонов адресов) , будет использована лишь небольшая часть всего 47-битного адресного пространства, поэтому размещение кода в этом 47-битном пространстве будет по-прежнему очень случайным. Размещение кода IIUC, ASLR также не является полностью случайным; ровно настолько, чтобы было трудно предсказать, где что-нибудь будет.

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

Ну раз уж с asm.js дней всего 1000. Потом выделение памяти просто выкидывает. Возможно, нам придется это исправить, но даже со многими супермодульными приложениями (с множеством отдельных модулей wasm каждое), использующих один и тот же процесс, я не могу представить, что нам понадобится слишком много большего. Я думаю, что Memory отличается от простых старых ArrayBuffers тем, что приложения, естественно, не захотят создавать тысячи.

1000 кажется разумным пределом. Я спрошу у сотрудников службы безопасности.

Как я уже упоминал выше, добавление обещанияeval (bytecode, importObj) API хорош, но теперь он ставит разработчика в трудное положение, потому что теперь им приходится выбирать между повышением производительности на некоторых платформах и возможностью кэшировать свой скомпилированный код на всех платформах. Похоже, нам нужно решение, которое интегрируется с кешированием, и это то, о чем я размышлял выше с явным API кеширования.

Верно. Я вижу несколько способов заставить такой API работать. Дрянный, но практичный API - это перегрузить eval:

  1. instancePromise = eval (байт-код, importObj)
  2. instancePromise = eval (модуль, importObj)

а затем у экземпляра есть геттер:

модуль = instance.module

Где модуль является клонируемой структурой.

Что ты думаешь об этом?

Новая идея: что, если мы добавим асинхронную версию нового экземпляра, скажем, WebAssembly.instantiate, и, как и в случае с WebAssembly.compile, мы скажем, что все должны использовать асинхронную версию? Это то, что я все равно обдумывал, поскольку создание экземпляра может занять несколько мс, если используется исправление. Затем мы говорим в спецификации, что движок может выполнять дорогостоящую работу либо при компиляции, либо при создании экземпляра (или ни в одном другом случае, если движок выполняет ленивую проверку / компиляцию!).

Это по-прежнему оставляет вопрос, что делать, когда скомпилированный модуль хранится в IDB, но это просто сложный вопрос, когда в любом случае существует несколько режимов кодогенерации. Одна идея состоит в том, что модули, которые хранятся в IDB или извлекаются из него, удерживают дескриптор своей записи IDB и добавляют в эту запись новый скомпилированный код. Таким образом, запись IDB будет лениво накапливать одну или несколько скомпилированных версий своего модуля и сможет предоставить то, что требуется во время создания экземпляра.

Часть IDB - это немного больше работы, но она кажется довольно близкой к идеалу с точки зрения производительности. WDYT?

Интригующе. Относительно моей идеи выше:

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

Есть три области, в которых ваше предложение не дает пользователю столько контроля, как мое:

  1. Дорогостоящая работа может происходить в одном из двух мест, поэтому пользователь должен спланировать, что любое из них будет дорогостоящим. У нас, вероятно, будет веб-контент, который плохо себя ведет, если один из них будет дорогим, потому что он был настроен для случаев, когда он оказался дешевым. В моем предложении есть одно место, где происходят дорогостоящие вещи, что приводит к большему единообразию между реализациями.
  2. Нет четко гарантированного пути для кэширования всех версий скомпилированного кода. С другой стороны, мое использование потоковой передачи модуля через API означает, что виртуальная машина может каждый раз наращивать модуль с большим количеством материалов, при этом позволяя пользователю управлять кешем. Итак, если в первый раз мы сделаем 4 ГБ, то это то, что мы будем кэшировать, но если мы не сможем сделать 4 ГБ во второй раз, мы потенциально сможем кэшировать оба (если пользователь кеширует instance.module после каждой компиляции).
  3. Необычные угловые случаи в браузере или другие проблемы могут иногда приводить к двойной компиляции в вашей схеме, потому что мы компилируем что-то одно на этапе компиляции, но затем понимаем, что нам нужно другое на этапе создания экземпляра. Моя версия никогда не требует двойной компиляции.

Так что мой мне нравится больше. Тем не менее, я думаю, что ваше предложение - это прогресс, поэтому мне оно определенно нравится.

Этот вопрос основан на том, как часто фрагментация приводит к быстрому распределению.
память (кстати, у вас 4 ГБ + максимальное поддерживаемое смещение или 8 ГБ) не работает. Если
вероятно, намного меньше 1%, тогда было бы не совсем неразумно
это может быть ситуация OOM.

В сценарии, когда пользователь просматривает веб-страницы и использует множество
маленькие модули WASM в быстрой последовательности, по-видимому, не все они живут в
однажды. В этом случае небольшой кеш из зарезервированных блоков размером 4 ГБ уменьшит
проблема.

Другая возможная стратегия - создать одну версию кода с
проверки границ, и если доступна быстрая память, просто перезапишите границы
проверяет с nops. Это уродливо, но это чертовски быстрее, чем
перекомпилируйте, и меньше места, чем две компиляции.

27 октября 2016 г., 21:03, pizlonator [email protected]
написал:

@mtrofin https://github.com/mtrofin

Автору модуля требуется 4 ГБ в качестве минимальной / максимальной памяти.

Это непрактично, поскольку на многих устройствах нет 4 ГБ физической памяти.
объем памяти. Кроме того, это сложно указать.

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

Я не думаю, что нам нужны двойные компиляции.

-
Вы получаете это, потому что подписаны на эту ветку.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/WebAssembly/design/issues/838#issuecomment -256738329,
или отключить поток
https://github.com/notifications/unsubscribe-auth/ALnq1F6CYUaq0unla0H6RYivUC8jfxIAks5q4PWIgaJpZM4Kh1gM
.

Это не просто ASLR: это также загрязнение страниц, распределителей и т. Д. Нам всем нужно поговорить с нашими специалистами по безопасности _, а также_ с разработчиками ядра / систем. Или мы можем заранее сообщить разработчикам об ограничениях, накладываемых каждым движком на «быстрый» Memory , и сделать его идиоматическим в API, чтобы его было сложно использовать неправильно.

Мы можем использовать все эти костыли, такие как nop или двойная компиляция, но зачем вообще костыли?

@jfbastien Я не думаю, что память PROT_NONE стоит записей таблицы страниц; Я думаю, что есть отдельная структура данных, которая содержит сопоставления, из которых таблица страниц заполняется лениво.

@pizlonator Мне нравится эта идея, и я вижу, что это то, что мы призываем всех использовать по умолчанию в учебных пособиях, инструментальной цепочке и т. д. Это также более сжато и легче преподавать, если вы можете просто игнорировать Module . Это также могло бы устранить озабоченность @ s3thompson по поводу

Однако я думаю, что нам не следует убирать WebAssembly.compile и конструктор Module : я представляю себе сценарии, в которых у вас есть «сервер кода» (обеспечивающий кэширование кода между разными источниками через IDB + postMessage ; это уже было специально обсуждено с некоторыми пользователями), которые хотят компилировать и кэшировать код без необходимости «подделывать» параметры создания экземпляра. (Также могут возникнуть ненужные накладные расходы (мусор, исправление и т. Д.) Из-за ненужного создания экземпляра.) И для тех же самых крайних случаев, когда требуется синхронная компиляция (через new Module ), нам нужно будет сохранить new Instance .

Итак, если вы согласны с этим, то это сводится к чисто аддитивному предложению двух упомянутых вами перегрузок WebAssembly.eval . Да?

Однако есть одна поправка: я думаю, что у нас не должно быть геттера module поскольку для этого потребуется Instance для хранения некоторых внутренних данных (а именно, байт-кода) в течение всего времени существования Instance ; прямо сейчас Module обычно можно использовать сразу после создания экземпляра. Это может предложить либо свойство данных (которое пользователь может удалить, хотя он, вероятно, забудет об этом), либо, возможно, третью версию eval которая возвращает пару {instance, module} ...

Наличие асинхронного одношагового API в качестве рекомендуемого случая для типичного монолитного приложения имеет смысл в качестве рекомендуемого шаблона.

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

Добавление двух предложенных вариантов eval кажется хорошим способом представить это.

Однако мне не нравится это имя, потому что в сознании людей (безопасности) оно будет объединено с js eval (на которое оно похоже в одном отношении, но не в плане захвата области видимости).
Как насчет WebAssembly.instantiate?

Ха, хороший момент, у eval есть немного репутации . +1 к WebAssembly.instantiate .

Что бы разработчик мог посоветовать при использовании асинхронного экземпляра?

@mtrofin Чтобы использовать WebAssembly.instantiate по умолчанию, если у них нет специальной схемы разделения кода / загрузки, которая требует компиляции Module s независимо от какого-либо конкретного использования.

@lukewagner Это кажется разумным.

Ха, хороший момент, у eval есть немного репутации. +1 к WebAssembly.instantiate.

Согласовано.

Итак, если вы согласны с этим, то все сводится к чисто аддитивному предложению двух упомянутых вами перегрузок WebAssembly.eval. Да?

Вот как это звучит.

Я думаю, что у нас не должно быть средства получения модуля, поскольку это потребует от экземпляра хранения некоторых внутренних данных (а именно, байт-кода) в течение всего времени существования экземпляра; прямо сейчас Модуль обычно может быть загружен сразу после создания экземпляра. Это может предложить либо свойство данных (которое пользователь может удалить, хотя он, вероятно, забудет об этом), либо, возможно, третью версию eval, которая возвращает пару {instance, module} ...

Конечно, кажется, что свойство данных лучше. Или если WebAssembly.instantiate всегда возвращает экземпляр, пару модулей.

Это правильно: предположим, вы WebAssembly.instantiate хотите получить вариант модуля fastmemory. Теперь вы получаете модуль и клонируете его структуру. Теперь этот модуль обязательно должен быть создан с помощью Memory -es, поддерживающего fastmemory.

@pizlonator Да, я могу прокрутить это в голове разными способами. Я думаю, что мне нравится возвращать пару немного лучше, так как это, вероятно, приведет к тому, что меньше людей случайно унесет неиспользованный Module .

@mtrofin Перекомпиляция все еще может быть необходима, когда вы снимаете Module с одного вызова instantiate и instantiate с новым импортом; Я думаю, что смысл этого добавления API в том, что это не будет обычным случаем, и это произойдет только тогда, когда это принципиально необходимо (например, у вас есть 1 модуль, имеющий доступ к двум типам памяти).

Этот поток становится длинным, похоже, он сходится, но чтобы быть на 100% уверенным, нам нужно написать код, который, как мы ожидаем, напишут разные пользователи:

  1. Асинхронное создание одного модуля.
  2. Асинхронное создание экземпляра модуля с разделением памяти с другими модулями.
  3. Синхронное создание одного модуля (я не думаю, что синхронный многомодуль полезен?).
  4. Кэширование для всего этого (как помещение в кеш, так и извлечение и создание экземпляра с памятью).
  5. Обновление одного модуля .wasm и кешированные загрузки других модулей.

Что-нибудь еще? Похоже, у @lukewagner есть идеи по

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

@jfbastien Я хотел бы понять для каждого фрагмента

@mtrofin Правильно, учитывая Module m , вы бы назвали WebAssembly.instantiate(m) который является асинхронным. Вы _ можете_ позвонить new Instance(m) и это может быть дорого, но это ничем не отличается от new Module(m) .

@jfbastien Предполагая, что когда вы говорите «асинхронное создание экземпляра», вы имеете в виду «асинхронную компиляцию и создание экземпляра», вот краткая версия:

  1. WebAssembly.instantiate(bytecode, imports)
  2. WebAssembly.instantiate(bytecode, imports) , где imports включает общую память
  3. new Instance(new Module(bytecode), imports)
  4. Во всех случаях вы можете получить Module , затем put что в IDBObjectStore . Позже вы возвращаетесь get a Module m и вызываете WebAssembly.instantiate(m, imports) .
  5. Здесь нет ничего особенного: вы WebAssembly.instantiate один модуль из байт-кода и instantiate остальное из Module s, взятых из IDB.

Следует ли нам рекомендовать использовать экземпляр синхронизации, если вы чувствуете, что можете использовать компиляцию синхронизации, и экземпляр async, если считаете, что вам следует использовать компиляцию async?

Кроме того, я обеспокоен тем, что разработчик теперь столкнется с более сложной системой: больше вариантов, которые обнаруживают оптимизацию, которую мы планируем сделать, и я не уверен, что у разработчика есть правильная информация, доступная для компромиссов. Если подумать с точки зрения разработчика, есть ли меньший набор проблем, которые им небезразличны и которые им было бы удобно выражать? Мы говорили о том, что разработчики имеют «оптимизацию за счет точных точек отказа» (это была повторная проверка границ). Альтернативой может быть флаг «оптимизировать»?

@mtrofin 99% того, что разработчики напишут (или сгенерировали для них с помощью инструментальной цепочки), будет WebAssembly.instantiate . Вы должны использовать API синхронизации только для специального сообщения «Я пишу JIT в wasm» и WebAssembly.compile если вы пишете какую-то систему совместного использования кода, поэтому я думаю, что учебные пособия «Приступая к работе» будут охватывать исключительно WebAssembly.instantiate .

@lukewagner Я заметил, что вы добавили импорт в # 3 new Module () выше. Я думаю, что добавление его в WebAssembly.compile - хорошая идея, которая расширяет возможности.
Таким образом, если вы хотите намекнуть о памяти во время компиляции, вы можете.
Если позже вы снова создадите экземпляр с другим импортом, особенно синхронно, вы можете получить икоту.

Итак, сводка изменений (чтобы я понял):

  • Добавление WebAssembly.instantiate (байты, импорт) возвращает обещание {instance :, module:}
  • Добавление WebAssembly.instantiate (module, import) возвращает обещание {instance :, module:}
  • Переход на новый модуль (байты , импорт ) возвращает модуль
  • Изменение на WebAssembly.compile (байты , импорт ) возвращает обещание экземпляра

Укажите где-нибудь ожидание, что создание экземпляра будет быстрым, если импорт из компиляции соответствует экземпляру.

WDYT?

Ой, я хотел поместить импорт в качестве аргумента в Instance . Я не уверен, что это необходимо для Module или compile . [Изменить: потому что, если бы они у вас были, вы бы просто позвонили instantiate ]

Таким образом, это будет означать, что для случая сквозной асинхронности вы можете знать, что будете привязаны к 4 ГБ памяти для взлома, но не для ядра JIT-фильтра или элемента, скомпилированного в фоновом режиме (если вы также не создаете бросок прочь экземпляр)?

+1 для сосредоточения руководства на асинхронной паре компиляции и создания экземпляра - делает сообщение простым и скрывает сложность проблемы решения от разработчика.

Да, я думаю, мы все согласны с тем, что мы должны указать людям на:
Первый раз:
WebAssembly.instantiate (байты, импорт) -> обещание {модуль, экземпляр} (модуль кеширования для indexeddb)
Второй раз:
WebAssembly.instantiate (модуль, импорт) -> обещание {модуль, экземпляр}

Есть ли возражения против того, что это основной шаблон?

Разрываюсь на импорте для компиляции / нового модуля. Похоже, это может быть полезным намеком.
Тем не менее, я был бы готов упомянуть об этом как о возможности и отложить добавление этого аргумента (он может быть необязательным) в Post-MVP.

Мысли?

@mtrofin (ну, технически просто instantiate .)

@lukewagner (думаю, это то, что имел в виду

@lukewagner , @flagxor ОК, но мы сохраняем API асинхронной компиляции, верно?

Как насчет такого сценария: вы получаете такое приложение, как PhotoShop, с множеством плагинов. Каждый плагин представляет собой модуль wasm. Вы запускаете основное приложение, и вам удается выделить волшебный объем памяти, который запускает fastmemory (кажется разумным для этого сценария - одно приложение, требуется память).

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

Если мы купим этот сценарий, то он почувствует, что может быть полезно передать некоторый дескриптор памяти (для ясности, без фактической поддержки памяти) в API компиляции.

Да, должно быть возможно (даже рекомендуется) передать Memory в компиляцию.

@mtrofin Верно, compile для расширенного использования. Я полагаю, что этот пример плагина является допустимым случаем, когда вы хотите _компилировать_, _и_ у вас есть Memory , но вы не хотите создавать экземпляр (пока).

@pizlonator Между прочим , я хотел спросить раньше, предполагая, что взлома «выбросить, если более 1000 карт размером 4 ГБ на процесс» достаточно для решения проблем ASLR / безопасности, есть ли еще_ необходимость в медленном / быстром режиме из-за платформы ограничения квоты виртуального адреса? Потому что, если бы его не было, было бы неплохо, если бы это не учитывалось даже в производительности даже для опытных пользователей. (API instantiate кажется полезным добавить по другим причинам, о которых мы упоминали, конечно.)

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

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

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

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

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

Это не новые вопросы, они обсуждаются уже много лет. Требуется управление ресурсами памяти, и его нужно согласовывать с генерацией кода.

@lukewagner Я так думаю, потому что, если мы ограничим 1000 модулей, я бы побеспокоился, что допуски не будут достаточно большими.

  • Я бы беспокоился о всплытии атаки, когда этот потолок должен был упасть.
  • Я бы побеспокоился об оптимизации в другом месте стека, уменьшающей объем доступного нам виртуального адресного пространства, что затем потребовало бы от нас переоценки, достаточно ли низок потолок.
  • Я бы беспокоился о предотвращении стилей программирования, которые намеренно создают тысячи модулей. Например, я знаю, что большинство клиентов фреймворка JavaScriptCore создают виртуальную машину, выполняют небольшую работу, а затем уничтожают ее. Если WebAssembly используется из JS таким же образом, как и JSC из Objective-C, то для того, чтобы заставить его работать в 64-битных системах, GC должен знать, что если вы выделяете 1000 ячеек памяти - даже если каждая из них была маленькой - тогда вы должны GC на случай, если следующее выделение должно быть успешным на том основании, что эти 1000 ячеек теперь недоступны. Возможность выделять память, отличную от 4 ГБ, после того, как уже существует, скажем, 10 активных модулей памяти размером 4 ГБ, означало бы, что сборщику мусора не пришлось бы сильно менять свою эвристику. При выделении 1001-го модуля в цикле instantiate-> run-> die не нужно было бы выполнять сборщик мусора. Это будет преимуществом для шаблонов, которые используют крошечную память. Все, что меньше 1 МБ, начинает иметь смысл иметь 1000 из них. Я могу представить себе людей, делающих полезные вещи в 64 КБ.
  • Я бы беспокоился о том, что это будет менее полезно для других контекстов JavaScript. Я хочу оставить дверь открытой для клиентов JSC C API и Objective-C API, чтобы они имели доступ к WebAssembly API из своего JS-кода. Эти клиенты, вероятно, предпочтут небольшой лимит на количество выделяемых нами 4 ГБ памяти. Заманчиво даже сделать эту квоту настраиваемой в таком контексте.

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

@pizlonator Достаточно

Что касается того, почему меня не беспокоят те элементы, которые вы упомянули (в настоящее время):

  • Возможно, потребуется поднять лимит; это просто.
  • При любом разумном пределе будет использоваться только небольшая часть общего 64-битного адресного пространства, поэтому я не знаю, что это за вектор атаки; у определенного контента есть много способов для самого OOM
  • Мы увеличиваем эвристику GC соразмерно размеру резервирования, и, таким образом, перемешивание через Memory s только приводит к более агрессивному GC. Больше GC - это не очень хорошо, но я не уверен, что это будет обычная практика.

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

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

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

Пт, 28 октября 2016 г., в 2:15, JF Bastien [email protected]
написал:

Да, должна быть возможность (даже поощряться) передавать память в
компиляция.

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

-

Вы получили это, потому что прокомментировали.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/WebAssembly/design/issues/838#issuecomment -256805006,
или отключить поток
https://github.com/notifications/unsubscribe-auth/ALnq1KXrUWaegRZwEhznmT1YcyI33IN9ks5q4T6TgaJpZM4Kh1gM
.

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

Итак, что осталось сделать, чтобы решить эту проблему? Можно обновить http://webassembly.org/getting-started/js-api , что я могу сделать. Другой вариант - для двоичного файла это по умолчанию (звучит хорошо @kripken?). @titzer реализует ли Canary WebAssembly.instantiate ?

Что-нибудь еще?

@lukewagner : не уверен, о чем вы спрашиваете, обсуждение в этом выпуске очень долгое. Вы хотите изменить двоичный файл из текущего API синхронизации WebAssembly.Instance, который он использует для использования одного из предлагаемых здесь новых API на основе обещаний? Это необходимо - мы убираем старый способ?

@kripken Верно, переход на использование WebAssembly.instantiate . Мы не удаляем старый способ, но новый способ более эффективен и предназначен для использования по умолчанию.

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

@kripken Я не уверен, что понимаю: текущий подход заключается в том, чтобы вообще не использовать асинхронный API?

Да . См. Эту проблему для добавления асинхронных материалов.

Я полагаю, что у drainJobQueue() а в V8 я слышал, что есть %RunMicroTasks() . Похоже, вы могли бы просто включить test WebAssembly.instantiate и использовать его по умолчанию.

Конечно, но во-первых, поддержка Promise может быть в последней версии node.js, но ее нет в обычно используемых версиях (например, версия по умолчанию в дистрибутивах Linux). И, во-вторых, более серьезная проблема заключается в том, что когда мы генерируем HTML, у нас есть контроль над тем, как загружается страница (emcc излучает код загрузки для пользователя), в то время как когда мы генерируем JS, предполагается, что JS просто выполняется линейно, и пользователи зависят от при этом, например, у них может быть другой тег сценария сразу после этого JS. В этом случае пользователь пишет свой собственный код загрузки.

В результате обоих из них, как упоминалось ранее, мы можем использовать API-интерфейсы Promise при отправке HTML (тогда вы определенно не находитесь в оболочке и имеете контроль над загрузкой), но не при отправке JS. Там мы можем только задокументировать это.

Есть ли в Node версии, которые поддерживают WebAssembly, но не поддерживают Promise? Интересуют ли люди Node эти версии?

Я не понимаю простой JS. Если вы всегда возвращаете обещание, разве это не сработает (пользователи кода должны использовать обещание)?

Я не знаю ответа на первый вопрос, но полифил может позволить wasm работать на версии узла, в которой отсутствуют обещания. Хотя, возможно, также можно будет выполнять полифилы промисов, поскольку node уже некоторое время имеет версию setTimeout, я думаю, но я тоже не уверен в этом.

О прямой проблеме: emcc генерирует JS, который устанавливает среду выполнения и подключается к скомпилированному коду. Некоторые JS в теге скрипта сразу после него могут вызывать этот скомпилированный код, например, используя ccall . Другими словами, JS-вывод emcc не является обещанием, поэтому я не уверен, что вы подразумеваете под «возвратом обещания» - кто его вернет и кто получит? Но в любом случае, как упоминалось ранее, рекомендуется, чтобы emcc генерировал HTML, и в этом случае мы можем создать код асинхронной загрузки. Просто некоторые пользователи предпочитают более напрямую управлять загрузкой. Нам нужно будет побудить их использовать async wasm, если это лучше.

Узел IMO с WebAssembly, но без Promises - это не ограничение дизайна, о котором нам следует беспокоиться. В этом контексте полифил для WebAssembly довольно глуп.

Вы описываете, что делает код сегодня. Я не совсем понимаю это, но хотел бы сделать резервную копию: я хочу, чтобы код на веб-страницах использовал Promise API. Emscripten является производителем такого кода. Я не понимаю, что мешает ему выдавать код, использующий обещания. Я в полном порядке, если вы скажете: «Это значительная работа, потому что сегодня так не работает, но мы до нее доберемся». Но из нашего обсуждения я не уверен, что вы это говорите.

Проблема, которую вы указываете, касается только использования асинхронных API-интерфейсов для кэширования? Думаю, это начало, но в конечном итоге я хотел бы добраться до того, где асинхронный API используется даже при первой загрузке.

Почему бессмысленно использовать полифил на узле? По-прежнему кажется полезным в этом контексте, даже если меньше, чем в других случаях :)

Опять же: Emscripten будет использовать API обещаний при отправке HTML. И это рекомендуемый путь. Итак, ответ на ваш вопрос - «да». Это несущественная работа. Это в общих чертах обрисовано в этом выпуске, который, да, фокусируется на кэшировании, но я добавил примечания из (старого) автономного обсуждения, что при этом мы также должны сделать кучу других асинхронных оптимизаций там, поскольку мы можем и это тривиально.

Это снимает ваши опасения?

Все, что я говорю, это то, что когда Emscripten испускает JS - менее рекомендуемый путь - тогда гарантии этого вывода не согласуются с кодом, выполняющим некоторую асинхронную магию внутри. Мы бы нарушили код людей, чего мы не хотим делать. Как я уже сказал, кто-то может написать JS, который запускается синхронно сразу после этого JS, предполагающего, что он готов. Так что в этом случае мы не сможем использовать обещания. Представьте себе это:

`` ''

`` ''

doSomething требуется, чтобы Module.my_func существовал. Если output.js только что вернул обещание, значит, его еще нет. Так что это будет переломное изменение.

Теперь это имеет смысл?

Почему бессмысленно использовать полифил на узле? По-прежнему кажется полезным в этом контексте, даже если меньше, чем в других случаях :)

Полифил для wasm - это не глупо. Удовлетворять установки Node, у которых нет wasm, полифилить его и не иметь обещания, но не полифилить его - глупо. Это наполовину осла. Они должны получить вторую половину попки 😁

Опять же: Emscripten будет использовать API обещаний при отправке HTML. И это рекомендуемый путь. Итак, ответ на ваш вопрос - «да». Это несущественная работа. Это в общих чертах обрисовано в этом выпуске, который, да, фокусируется на кэшировании, но я добавил примечания из (старого) автономного обсуждения, что при этом мы также должны сделать кучу других асинхронных оптимизаций там, поскольку мы можем и это тривиально.

Это снимает ваши опасения?

Хорошо, это хорошо! Пока большинство веб-страниц используют обещание API, я счастлив.

[вырезать]

Теперь это имеет смысл?

да. Спасибо за объяснение.

С моей точки зрения, Emscripten больше не занимается только выпуском JS! Ваш пример имеет смысл для Ye Olden Codes, но новые вещи должны предполагать обещания IMO.

Кстати, я посмотрел на переключение webassembly.org/demo на использование instantiate и это немного сложно, потому что текущий синхронный new Instance происходит в контексте, который хочет синхронного результата. Итак, как только мы обновим Binaryen, чтобы по умолчанию выдавать instantiate , было бы неплохо пересобрать демонстрацию AngryBots с нуля.

Да, но учтите, что перестройки с нуля может быть недостаточно - я считаю, что Unity использует собственную загрузку и HTML-код. Поэтому нам нужно будет задокументировать и сообщить об этой проблеме, как упоминалось ранее, чтобы они могли делать необходимые вещи (или, может быть, мы можем заставить их позволить emcc выдавать html, но я не знаю, возможно ли это для них).

Да, но учтите, что перестройки с нуля может быть недостаточно - я считаю, что Unity использует собственную загрузку и HTML-код. Поэтому нам нужно будет задокументировать и сообщить об этой проблеме, как упоминалось ранее, чтобы они могли делать необходимые вещи (или, может быть, мы можем заставить их позволить emcc выдавать html, но я не знаю, возможно ли это для них).

Учитывая потенциальные Недостатки не используя WebAssembly.instantiate API, я думаю , что стоит с просьбой рассмотреть вопрос об использовании его.

Задокументированы ли эти недостатки? Четкие инструкции по этому поводу на главном веб-сайте wasm или на вики-странице emscripten wasm были бы удобными для людей.

Я сам пробежался по этому длинному выпуску, и пока не понимаю его минусов, так что я тоже хочу это прочитать :)

@kripken Проблема с текущим кодом заключается в том, что binaryen / emscripten предоставляет только необходимый импорт (необходимый в качестве аргументов для instantiate ) одновременно с синхронным запросом экспорта. Если импорт можно сделать доступным «заранее», то довольно просто прикрепить WebAssembly.instantiate к хвосту асинхронного XHR (как я сделал в текущей демонстрации с помощью async compile ). Так что я не думаю, что это потребует большой работы со стороны Unity. Кроме того, из того, что я видел , наша текущая версия wasm-сборки AngryBots не оптимальна и в любом случае требует доработки.

О, я не понимал, что наличие импорта до того, как начнется wasm XHR, является ключевым моментом. Тогда это намного сложнее. Так что большая часть того, что я сказал раньше, неверно.

Чтобы иметь возможность импорта, нам необходимо загрузить, проанализировать и запустить весь клей JS. Если мы сделаем все это до того, как wasm XHR даже начнется, тогда это будет совсем другая схема загрузки и набор компромиссов, чем сейчас. В частности, для малых и средних проектов, возможно, это даже не будет ускорением, я думаю, нам нужно будет это измерить - если мы еще не сделали этого?

Для Unity это будет непросто. Это потребует значительных изменений в коде, который излучает emcc, чтобы клей JS можно было запустить до того, как скомпилированный код будет готов.

Возможно, мы хотели бы рассмотреть новую модель генерируемого JS, один JS-файл для импорта, один JS-файл для всего остального? И это будет подписка, чтобы мы никого не сломали. Как бы то ни было, об этом много думают, и без измерений трудно угадать, что является оптимальным.

@kripken Не до XHR, а после его завершения и за некоторое время до того, как мы начнем запускать скрипт, который хочет синхронного доступа к объекту экспорта. Я ожидал, что это может быть так же просто, как поместить этот код, использующий экспорт, в некоторый обратный вызов, вызываемый при разрешении создания экземпляра.

Хм, я думаю, что тогда я все еще не полностью понимаю это, извините (в частности, я не понимаю, почему асинхронность взаимодействует с получением импорта - может ли выгода от того, что импорт не работает синхронно?). Но похоже, что проблемы, о которых я упоминал выше, по-прежнему актуальны, даже если это происходит после завершения XHR, то есть теперь у нас есть один скрипт, который генерирует импорт, а также получает экспорт. Разделение этого может привести к компромиссу - нам просто нужно измерить, когда у нас будет время.

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

Подпись instantiate - WebAssembly.instantiate(bytes, importObj) , поэтому для запуска асинхронной компиляции + создания экземпляра необходимо передать importObj .

Говоря в автономном режиме, @lukewagner впечатлил меня, что основная проблема здесь

  1. Предоставление памяти при компиляции.
  2. Обеспечение всего импорта при компиляции (надмножество предыдущего).
  3. Делаем все это асинхронно.

Учитывая, как в настоящее время работает инструментальная цепочка, сделать 2 + 3 сложно, как описано выше, потому что это сломает существующих пользователей. Мы можем это сделать, но, возможно, не хотим, чтобы он был включен по умолчанию, по крайней мере, на начальном этапе - нам нужно будет проконсультироваться с членами сообщества и т.д. можно сделать, добавив слой косвенного обращения либо к импорту, либо к экспорту).

Но некоторые другие варианты тривиально просты в использовании:

  • 1 + 3 потребует нового API, например instantiate(bytes, Memory) -> Promise . Причина, по которой это легко использовать, заключается в том, что память может быть создана в любом случае на ранней стадии (в то время как почти весь другой импорт - это JS-функции, которые у нас не могут быть на раннем этапе).
  • 2 сам по себе, без 3, т. Е. new Instance(bytes, imports) . То есть синхронная компиляция по двоичным данным + импорт. Причина, по которой это легко использовать, заключается в том, что наш текущий код делает это: instance = new WebAssembly.Instance(new WebAssembly.Module(getBinary()), imports) поэтому мы просто сворачиваем это в 1 вызов API.

Думаю, последний вариант имеет смысл. По сути, это означает добавление синхронизирующей версии нового API, что делает вещи более симметричными с существующей опцией синхронной компиляции. И я не вижу причин связывать новую оптимизацию знания памяти во время компиляции с асинхронной компиляцией? (асинхронность - это здорово, но отдельная тема?)

Я предлагаю метаобъекты, которые описывают импорт (память), чтобы снять ограничение, которое необходимо выделить для импорта перед компиляцией. Тогда метод instantiate может выдать ошибку, если предоставленная память не соответствует ожидаемой и не будет отложена повторная компиляция.

Также было бы очень полезно иметь возможность компилировать перед выделением линейной памяти на устройстве с ограниченным объемом памяти, а также иметь возможность оптимизировать компиляцию для памяти, выделенной на нуле в линейном адресном пространстве, и, возможно, для памяти с защитными зонами, и для оптимизировать для памяти с фиксированным максимальным размером, который может быть степенью двойки плюс зона разлива. Этот метаобъект также может использоваться декодером / перезаписчиком пользователя wasm для выдачи кода, оптимизированного для согласованных характеристик памяти.

Это то, что предлагается как необходимое в начале этого проекта много лет назад!

@kripken Хотя API-интерфейсы синхронизации, я считаю, технически необходимы, они определенно должны быть нерекомендуемым путем, иначе мы введем тонны ненужного мусора основного потока, регресс по сравнению с asm.js +

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

Давайте уменьшим масштаб и на секунду поговорим о пользовательском опыте.


Вот сравнение загрузки демонстрации AngryBots асинхронно (через asm.js), слева и синхронно (через WebAssembly в V8), справа.

comparison

Синхронная компиляция создает ужасные условия для пользователя и приводит к нарушению индикаторов выполнения или любых других визуальных индикаторов загрузки приложения.

Какими бы ни были усилия, я думаю, нам нужно работать вместе, чтобы убедиться, что Emscripten, Unity и другие инструменты экспортируют асинхронно загружая WebAssembly по умолчанию. cc @jechter @juj Мало того, я думаю, нам нужно сделать недопустимо трудным для разработчиков попадание в ловушку написания кода синхронной загрузки.

Нам нужно явно поощрять WebAssembly.compile & WebAssembly.instantiate и препятствовать new WebAssembly.Module & new WebAssembly.Instance .


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

Вот запись, полученная с помощью панели производительности DevTools:

screen shot 2016-12-28 at 1 26 59 pm

На моем MacBook Air требуется 30 секунд, чтобы отобразить какой-либо индикатор выполнения.

Что занимает это время? Давайте увеличим масштаб до ~ 20 секунд после загрузки модуля wasm, когда основной поток полностью заблокирован:

screen shot 2016-12-28 at 2 18 36 pm

Компиляция занимает ~ 20 секунд, а создание экземпляра занимает ~ 2 секунды.

Обратите внимание, что в этом случае загрузчик Unity уже вызывает асинхронный WebAssembly.compile если он поддерживается, поэтому 20 секунд - это потому, что V8 все еще выполняет синхронную компиляцию под капотом. cc @titzer @ flagxили это то, что V8 действительно нужно исправить.

Задержка создания экземпляра 2s происходит из-за того, что код загрузчика Unity вызывает синхронный new WebAssembly.Instance . Это то, что нам действительно нужно исправить как в коде Unity, так и в Emscripten.


Я думаю, также стоит упомянуть, что это не просто риск того, что разработчик выстрелит себе в ногу или нет. Среднестатистическая веб-страница включает в себя десятки сторонних скриптов: все эти скрипты потенциально могут включать в себя WebAssembly, прерывающий верхний уровень документа.

(Если вы хотите изучить трассировку более подробно, вы можете просмотреть полную временную шкалу здесь: https://chromedevtools.github.io/timeline-viewer/?loadTimelineFromURL=https://www.dropbox.com/s/ noqjwql0pq6c1wy / wasm? dl = 0)

Я на 100% согласен с тем, что async - это здорово :) Но я говорю, что он ортогонален оптимизации получения памяти одновременно с компиляцией модуля. И что мы не можем тривиально получить асинхронность + эту оптимизацию - мы можем получить эту комбинацию, но либо за счет некоторых накладных расходов, либо за счет времени, если мы введем для него новый флаг и найдем способ сделать его по умолчанию .

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

Поскольку разработчики выбирают wasm, я думаю, имеет смысл воспользоваться возможностью, чтобы немного изменить структуру верхнего уровня с новым значением по умолчанию (с возможностью отказаться от старого поведения, если это необходимо). Люди, использующие синхронизацию

@kripken Я думаю, вы пришли к другим выводам, чем я, @lukewagner и @ s3thompson , потому что для вас самое важное - предложить плавный переход с asm.js для существующих разработчиков.

Это верно?

Я согласен, что это серьезная проблема. Я вешу меньше, потому что IMO с WebAssembly привлекает гораздо больше разработчиков, чем было у asm.js. Я бы хотел избежать ожесточения ранних последователей, но существующие разработчики IIUC довольно гибки и хотят асинхронной компиляции.

Если мы предположим, что они хотят асинхронной компиляции и готовы провести рефакторинг некоторых, чтобы получить ее, тогда все, что останется, - это иметь память во время компиляции, что и предоставляет этот API. Это очень желательно, потому что позволяет избежать ловушек.

Ранее вы выразили обеспокоенность объемом работы, проделанной на стороне Emscripten для поддержки этого. Вы все еще думаете, что это проблема?

FWIW, Unity 5.6 будет использовать WebAssembly.instantiate.

Йонас

28 декабря 2016 г. в 23:42 Сет Томпсон [email protected] написал:

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

Давайте уменьшим масштаб и на секунду поговорим о пользовательском опыте.

Вот сравнение загрузки демонстрации AngryBots с асинхронными вызовами (через asm.js), левыми и синхронными вызовами (текущая реализация WebAssembly), справа.

Синхронная компиляция создает ужасные условия для пользователя и приводит к нарушению индикаторов выполнения или любых других визуальных индикаторов загрузки приложения.

Какими бы ни были усилия, я думаю, нам нужно работать вместе, чтобы убедиться, что Emscripten, Unity и другие инструменты экспортируют асинхронно загружая WebAssembly по умолчанию. cc @jechter @juj Мало того, я думаю, нам нужно сделать недопустимо трудным для разработчиков попадание в ловушку написания кода синхронной загрузки.

Нам нужно явно поощрять WebAssembly.compile и WebAssembly.instantiate и препятствовать созданию нового WebAssembly.Module и нового WebAssembly.Instance.

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

Вот запись, полученная с помощью панели производительности DevTools:

На моем MacBook Air требуется 30 секунд, чтобы отобразить какой-либо индикатор выполнения.

Что занимает это время? Давайте увеличим масштаб до ~ 20 секунд после загрузки модуля wasm, когда основной поток полностью заблокирован:

Компиляция занимает ~ 20 секунд, а создание экземпляра занимает ~ 2 секунды.

Обратите внимание, что в этом случае загрузчик Unity уже вызывает асинхронный WebAssembly.compile, если он поддерживается, поэтому 20 секунд - это потому, что V8 все еще выполняет синхронную компиляцию под капотом. cc @titzer @ flagxили это то, что V8 действительно нужно исправить.

Задержка создания экземпляра 2s происходит из-за того, что код загрузчика Unity вызывает синхронный новый WebAssembly.Instance. Это то, что нам действительно нужно исправить как в коде Unity, так и в Emscripten.

Я думаю, также стоит упомянуть, что это не просто риск того, что разработчик выстрелит себе в ногу или нет. Среднестатистическая веб-страница включает в себя десятки сторонних скриптов: все эти скрипты потенциально могут включать в себя WebAssembly, прерывающий верхний уровень документа.

(Если вы хотите изучить трассировку более подробно, вы можете просмотреть полную временную шкалу здесь: https://chromedevtools.github.io/timeline-viewer/?loadTimelineFromURL=https://www.dropbox.com/s/ noqjwql0pq6c1wy / wasm? dl = 0)

-
Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub или отключите чат.

@jfbastien Может быть, я не понимаю, что вы подразумеваете под «выводами». Я в основном просто представляю здесь варианты. У меня самого нет вывода.

Если нам нужна опция «Память во время компиляции» прямо сейчас, я предложил несколько вариантов, которые позволят нам получить ее как можно скорее, тривиально изменив нашу текущую синхронизирующую компиляцию.

Или, если мы хотим, чтобы эта опция была асинхронной, я предложил вариант («1 + 3», т. Е. Не получать весь импорт во время компиляции, только память), который также может позволить нам получить его как можно скорее.

Или, если мы хотим сосредоточиться сейчас на асинхронной версии этой опции с текущим API (а не «1 + 3»), тогда мы тоже можем это получить, просто потребуется некоторое тщательное планирование, потому что это будет критическое изменение. Я не думаю, что у нас есть возможность решить сломать существующих пользователей, поэтому нам нужно будет проконсультироваться с сообществом. Возможно, будет немного проблем, и мы можем просто сделать это, и в этом случае, сколько усилий будет зависеть от того, сколько накладных расходов мы готовы терпеть - если мы вообще не можем принять какие-либо накладные расходы, то это может быть много. Или, возможно, возникнут опасения, что является моей личной интуицией - любое критическое изменение должно выполняться постепенно - в этом случае это займет больше времени, мы, вероятно, начнем с нового варианта и в конечном итоге планируем сделать его по умолчанию.

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

Или, если мы хотим сосредоточиться сейчас на асинхронной версии этой опции с текущим API (а не «1 + 3»), тогда мы тоже можем это получить, просто потребуется некоторое тщательное планирование, потому что это будет критическое изменение. Я не думаю, что у нас есть возможность решить сломать существующих пользователей, поэтому нам нужно будет проконсультироваться с сообществом. Возможно, будет немного проблем, и мы можем просто сделать это, и в этом случае, сколько усилий будет зависеть от того, сколько накладных расходов мы готовы терпеть - если мы вообще не можем принять какие-либо накладные расходы, то это может быть много. Или, возможно, возникнут опасения, что является моей личной интуицией - любое критическое изменение должно выполняться постепенно - в этом случае это займет больше времени, мы, вероятно, начнем с нового варианта и в конечном итоге планируем сделать его по умолчанию.

Конечно, я понимаю:

  1. Какие накладные расходы?

    • Являются ли эти накладные расходы присущими Async + Memory-at-compile-time, или это ограничения реализации, которые можно исправить позже? ИМО, если они присущи A + M, мы должны исправить API как можно скорее.

    • IIUC накладные расходы являются временным явлением либо для импорта, либо для экспорта и не присущи A + M, верно? Не могли бы вы подробнее рассказать об этом?

  2. О каких пользователях идет речь? Пользователи asm.js, которые хотят, чтобы тот же код был нацелен на wasm?

Иными словами: каково идеальное конечное состояние для WebAssembly, если бы у нас было бесконечное время и не было «наследства»? Я думаю, что мы разработали это идеальное конечное состояние, и вы указываете на препятствия на этом пути, но я все еще не уверен, что это так. Если это так, то я не уверен, что у меня достаточно информации, чтобы выяснить, нужна ли WebAssembly временная задержка для облегчения перехода или временная нагрузка приемлема для подмножества пользователей Emscripten (и каких пользователей).

О накладных расходах в некоторых вариантах: Как описано выше, сложность заключается в том, что мы должны отправлять импорт и получать экспорт синхронно в настоящее время, и что у нас нет импорта JS, пока JS не будет готов (но у нас есть память !). Один из способов обойти это - добавить уровень косвенного обращения к импорту или экспорту. Например, мы могли бы предоставить преобразователи вместо истинного импорта на очень раннем этапе (в HTML, до JS), поэтому мы, кажется, предоставляем их синхронно (но это просто преобразователи, которые легко создать еще до того, как у нас появится JS). . Позже, когда у нас будет JS, мы сможем обновить преобразователи, чтобы они указывали на нужное место. Это добавит накладных расходов на другой вызов JS и поиск объекта JS для каждого вызова импорта. Также некоторые накладные расходы на размер кода и запуск.

О нарушении работы пользователей: мы хотим, чтобы существующие пользователи emscripten могли снимать флажок и получать работу wasm . Многие пользователи и партнеры этому рады. Это позволяет им сравнивать asm.js и wasm, а также позволяет проектам, на перенос которых они потратили усилия, получить выгоду от wasm без каких-либо дополнительных усилий по переносу. И это позволяет избежать риска того, что, если им также потребуется асинхронизировать свой стартовый код при переносе на wasm, и что-то сломается, они могут без надобности винить wasm.

что у нас нет импорта JS, пока JS не будет готов (но у нас есть Память!)

Это кажется случайным и не то, что мы должны навсегда запекать во времени с помощью API. Кроме того, по причинам, которые объяснил все равно нужно, чтобы создание экземпляров было асинхронным. Итак, я согласен с @jfbastien, что у нас есть идеальный API конечного состояния, и мы не должны идти на компромисс здесь.

О нарушении работы пользователей: если мы предложим простой путь миграции (например, событие / обещание "onload"), то пользователям будет легко мигрировать, и все основные перфомансы будут побеждены пряником. Я не думаю, что у нас есть доказательства того, что точная обратная совместимость исходного кода asm.js является жестким требованием для конфигурации по умолчанию; у нас есть много примеров совершенно противоположного: пользователи готовы делать все, что угодно, чтобы достичь оптимальной производительности, поскольку в этом, конечно же, все дело.

Говоря с @lukewagner в автономном режиме, мы думаем, что лучше всего начать с включения создания экземпляра wasm в рекомендуемой по умолчанию настройке в emscripten, добавив косвенный слой (как описано выше, но для экспорта). Вероятно, в большинстве случаев это будет иметь незначительные накладные расходы. Так что это дает нам преимущества, которые мы все хотим здесь.

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

@kripken отлично! Было бы полезно иметь диаграмму, показывающую разные экземпляры / JS / import / exports / memory / tables. Вы хотите переместить это обсуждение в другое место (репозиторий Emscripten / binaryen)? У меня есть мысленное представление о том, в чем, по моему мнению, должен быть организован код C ++, но к настоящему времени совершенно очевидно, что у вас нет такой же картины! У вас там больше опыта, поэтому я хотел бы извлечь уроки из этого и помочь, чем смогу.

@jfbastien : конечно. Я еще не понимаю, что вы ищете на диаграмме, но да, может быть, другое место лучше. Для реализации этого в emscripten существует проблема, упомянутая ранее, https://github.com/kripken/emscripten/issues/4711 , также не стесняйтесь открывать другую, если она не охватывает то, что вы хотите.

IIUC Emscripten теперь использует это по умолчанию. Закрытие.

В продолжение комментария @ s3ththompson обратите внимание, что синхронная компиляция и создание экземпляров полезны. Примечательно, что недавно я столкнулся с ситуацией, когда я хотел синхронно загрузить и скомпилировать модуль WebAssembly в Node.js ( v7.7.2 ). Если доступны только API, возвращающие обещания, это означает, что я не смогу обеспечить синхронный экспорт.

Принимая решение о предоставлении асинхронного, синхронизирующего или обоих API, помните, что контекст браузера - не единственная среда, в которой люди хотят использовать WebAssembly. Ряд людей, в том числе и я, заинтересованы в потенциале WebAssembly как эффективной цели компиляции в сочетании со средой выполнения Node.js, похожей на JVM. Хотя асинхронный импорт / экспорт может попасть в Node.js, синхронный импорт и экспорт останутся доминирующей моделью в обозримом будущем. В этом случае очень полезна возможность загрузить модуль WebAssembly и синхронно компилировать и создавать экземпляр этого модуля.

@kgryte Я должен был пояснить, что мой комментарий в первую очередь относится к браузеру как к контексту выполнения. Мы достигли поверхности API, которая по-прежнему предоставляет синхронные API. Браузеры могут налагать ограничение на размер модулей, передаваемых синхронным API (например, Chrome уже делает это), но это ограничение настраивается устройством для внедрения и не должно применяться к Node.

@ s3thompson Спасибо за разъяснения.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

JimmyVV picture JimmyVV  ·  4Комментарии

dpw picture dpw  ·  3Комментарии

artem-v-shamsutdinov picture artem-v-shamsutdinov  ·  6Комментарии

jfbastien picture jfbastien  ·  6Комментарии

thysultan picture thysultan  ·  4Комментарии