Скриптуем на WebAssembly, или WebAssembly без Web


    Представлять WebAssembly не нужно — поддержка уже есть в современных браузерах. Но технология годится не только для них.


    WebAssembly — кроссплатформенный байткод. Значит, этот байткод можно запустить на любой платформе, где есть его виртуальная машина. И для этого вовсе не нужен браузер и Javascript-движок.


    Далее — проверка концепции на прочность, инструментарий и первый скриптовый модуль.


    Зачем?


    Wasm-модули можно использовать в тех же случаях, что и скриптовые языки: для исполнения динамически загружаемой логики. Там, где используется Lua и Javascript. Но затраты на интерпретацию wasm меньше, чем у скриптовых языков, и на wasm можно применить больше оптимизаций. Ибо оптимизации эти делаются во время компиляции на исходной машине, а не интерпретации или JIT-компиляции на клиенте.


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


    Кроме скриптовых языков технологию можно сравнить с LLVM-байткодом и Java-машиной.


    Сравнение с LLVM-IR сделано уже в ходе разработки WebAssembly. Авторы аргументируют свой отказ ещё на этапе MVP так:


    • Портируемость: для различных архитектур целевой машины набор инструкций должен быть один. В общем случае для LLVM-IR это не так.
    • Стабильность: набор инструкций должен изменяться со временем только при сохранении обратной совместимости. LLVM такой цели не ставит.
    • Минимально возможный размер бинарного кода
    • Максимально быстрое декодирования
    • Быстрая компиляция: набор инструкций должен быть применим вместе с JIT-компиляцией, позволять достаточно быстрый процесс запуска приложения. LLVM-IR проектируется под ahead-of-time-компиляцию.
    • Минимальная неопределенность: поведение программ должно быть максимально предсказуемым. LLVM-IR же проектируется для возможностей оптимизации, значит, содержит множество вариантов неопределённого поведения (undefined behavior, UB)

    По сравнению с Java и её виртуальной машиной:


    • wasm не привязан к конкретному языку (или группе языков, с учётом Scala и Kotlin)
    • Java-машина неотделима от своей инфраструктуры и стандартных библиотек
    • JVM достаточно массивна
    • JVM требует вызова нативных функций поверх уже имеющейся инфраструктуры, что для низкоуровневых функций часто сложнее, чем разработка “с нуля”.

    WebAssembly может занять в инфраструктуре портируемого кода собственную нишу, где ни скриптовые языки, ни LLVM-IR, ни JVM не решают задачи эффективно.


    А какие это задачи?


    Идея использовать WebAssembly без web-окружения возникла из конкретной задачи. Необходимо создать модули с интерактивными графиками, которые бы работали на веб-сайте и в мобильном приложении. Первоначальный вариант решения: встроить Javascript-движок в мобильное приложение и передавать логику javascript-кодом. Но движки оказались достаточно массивными и сложными в устройстве (за исключением, пожалуй, JerryScript). Использование движка для одной небольшой задачи выглядело серьёзным оверинжинирингом. В этот момент мы пришли к выводу, что аналогичные модули на WebAssembly будут лучше из-за малого размера интерпретатора и более быстрой интерпретации.


    Другой вариант использования: компилировать в WebAssembly шаблоны для веб-страниц. Для этого достаточно создать backend к любимому шаблонизатору. Такие шаблоны достаточно просто запускать как на сервере через интерпретатор, так и в браузере стандартными средствами. Создать backend к шаблонизатору проще, чем портировать любимый шаблонизатор на любимую систему. Формально, backend проще сделать для кода на C, который после будет компилироваться в wasm.


    На сайте WebAssembly предлагаются и другие варианты использования:


    • Распространение игровых приложений в виде модулей (по аналогии с cocos2d-js, вместе с его обновлениями кода на ходу)
    • Исполнение ненадежного кода на стороне сервера (на самом деле, та же задача, что и с шаблонизаторами, но глобальнее)
    • Гибридные приложения для мобильных устройств
    • Запуск процессов сразу на нескольких вычислительных узлах

    Как?


    Собираем инструменты для сборки WebAssembly


    Для реализации задуманного нам нужен экспериментальный модуль WebAssembly из LLVM версии 5 (текущей стабильной) или старше.


    Будем использовать цепочку LLVM Webassembly backend -> LLVM байткод -> текстовое представление LLVM-IR -> Binaryen s2wasm -> Binaryen wasm-as


    Собираем LLVM

    Сборка занимает от 15 минут до часа и требует много памяти (особенно, при make -j8)


    # download LLVM-5 sources
    wget http://releases.llvm.org/5.0.0/llvm-5.0.0.src.tar.xz
    tar -xJf llvm-5.0.0.src.tar.xz llvm-5.0.0.src
    mv llvm-5.0.0.src llvm
    rm llvm-5.0.0.src.tar.xz
    
    cd llvm/tools
    
    # download clang sources
    wget http://releases.llvm.org/5.0.0/cfe-5.0.0.src.tar.xz
    tar -xJf cfe-5.0.0.src.tar.xz cfe-5.0.0.src
    mv cfe-5.0.0.src clang
    rm cfe-5.0.0.src.tar.xz
    
    cd -
    
    WORKDIR=`pwd`
    INSTALLDIR=`pwd`
    
    rm -rf llvm-build
    mkdir llvm-build
    cd llvm-build
    
    # For Debug build:
    # cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=$INSTALLDIR -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Debug $WORKDIR/llvm
    cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=$INSTALLDIR -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly $WORKDIR/llvm 
    make

    Собираем Binaryen
    git clone https://github.com/WebAssembly/binaryen.git
    cd binaryen
    cmake .
    make

    Собираем WABT
    git clone https://github.com/WebAssembly/wabt.git
    cd wabt
    git submodule update --init
    make

    Устанавливаем Rust
    curl https://sh.rustup.rs -sSf | sh
    source $HOME/.cargo/env
    rustup toolchain install nightly
    rustup target add wasm32-unknown-unknown
    rustup default nightly

    Пример сборки C/C++ с помощью makefile


    Сборка Rust
    rustc <source_file> --target=wasm32-unknown-unknown --crate-type=cdylib -C panic=abort -o <wasm_output>

    Собираем интерпретатор


    В качестве proof of concept можно использовать интерпретатор из WABT. Для подтверждения работы будем вызывать функцию из WebAssembly, которая вызывает функцию среды. Добавить импортируемые функции в WABT можно, например, вот так.


    Код на C
    extern void import_function(int);
    
    int export_function(int i_test) {
      import_function(i_test * 3);
      return ++i_test;
    }

    Код на Rust
    #![no_std]
    #![no_main]
    #![feature(lang_items)]
    
    #[lang = "panic_fmt"]  fn panic_fmt() -> ! { loop {} }
    
    mod wasm {
        pub fn _import_function(i: isize) -> isize {
            unsafe { import_function(i) }
        }
    
        extern {
            fn import_function(i: isize) -> isize;
        }
    }
    
    #[no_mangle]
    pub fn export_function(i_test: isize) -> isize {
        wasm::_import_function(i_test*2);
        let result = i_test+1;
        result
    }

    Запустить модуль можно так:


    <wasm-interp> <wasm-file> -E export_function

    Эти же модули можно использовать и в вебе, если реализовать требуемые импортируемые функции. Например, вот так.


    Замечания к коду


    • Rust добавляет в импортируемые функции rust_begin_unwind (хотя -C panic=abort гарантирует, что эта функция не будет вызвана). Потенциально проблему можно исправить на уровне rustc, на уровне оптимизации WebAssembly (через удаление неиспользуемых параметров). Как временное решение мы добавили rust_begin_unwind в список импорта в виде функции, которая не делает ничего.
    • Функции, возвращающие структуры будут преобразованы таким образом: Vec2 makeVec2(float x, float y) {...} в (func (; 2 ;) (param $0 i32) (param $1 f32) (param $2 f32). Возвращаемое значение было преобразовано в указатель (тип i32) на блок памяти, который будет хранить готовый объект. То есть, компилятор выполнил RVO. Для работы с такими функциями нужно предварительно распределить из памяти модуля требуемый блок, и вызывать функцию с указателем в качестве первого аргумента
    • Если хотите компилировать код с виртуальными функциями через Binaryen, вам пригодится патч:

    Патч для weak-символов в Binaryen
    --- a/src/s2wasm.h
    +++ b/src/s2wasm.h
    @@ -1320,7 +1320,7 @@ class S2WasmBuilder {
         }
         skipWhitespace();
         Address align = 4; // XXX default?
    -    if (match(".globl")) {
    +    if (match(".globl") || match(".weak")) {
           mustMatch(name.str);
           skipWhitespace();
         }

    Проектируем стандартную библиотеку


    WebAssembly модули умеют импортировать и экспортировать функции, но создать библиотеку предстоит самостоятельно: стандарт не определяет никакой стандартной библиотеки.


    Стандартная библиотека создается для интерпретатора и компилируется вместе с интерпретатором. Если задача требует исполнения wasm и нативно, и в браузере, вам нужно будет портировать вашу стандартную библиотеку на Javascript для совместимости. Например, для задачи интерактивных графиков написать cmath-совместимую обёртку и для интерпретатора, и для javascript.


    Что включать в стандартную библиотеку — отдельный сложный вопрос. В случае со скриптовыми языками, вам дают уже готовую универсальную библиотеку. Из которой некоторые функции вы будете вынуждены выключить (например, прямой доступ к файловой системе). В случае с wasm вы можете создать строгий специальный API, которым скрипты будут ограничены в их песочнице.


    Заключение


    WebAssembly — мощная технология, которую можно использовать и вне веб-окружения. Пока мы делаем только первые шаги и учимся использовать новые инструменты, проектировать системы по новым правилам. В будущем WebAssembly может стать одним из стандартов для портируемых исполняемых пакетов.


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


    В соавторстве с strelok2010


    Весь код здесь.

    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    Что дальше?

    • 24,1%Встроить интерпретатор в мобильные приложения на iOS и Android27
    • 25,9%Создать более-менее универсальную стандартную библиотеку29
    • 31,2%Описать внутреннее устройство WebAssembly (память, таблицы, импорты и экспорты)35
    • 10,7%Подробнее описать универсальные модули (работающие в веб-окружении и нативно)12
    • 1,8%Сделать автоматическую генерацию шаблонов кода для импортов/экспортов2
    • 6,2%Не нужно нам это всё7

    Похожие публикации

    Средняя зарплата в IT

    120 000 ₽/мес.
    Средняя зарплата по всем IT-специализациям на основании 9 370 анкет, за 1-ое пол. 2021 года Узнать свою зарплату
    Реклама
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее

    Комментарии 19

      –1

      Не знаком с WebAssembly, и поэтому есть вопросы:


      WebAssembly — кроссплатформенный байткод

      Разве это не позволяет интерпретирующему использовать всю ту же JIT-компиляцию?


      wasm не привязан к конкретному языку (или группе языков, с учётом Scala и Kotlin)

      JVM тоже не привязана к Java, она понимает свой байткод, в который могут компилироваться и другие языки (выше озвученные например). Группе языков? Есть интерпретаторы Python/Ruby/etc, но да, всё же это интерпретатор в интерпретаторе.
      Или я что-то не понимаю?


      JVM достаточно массивна

      Java 9 не спасёт ситуацию?


      Кстати, гуглятся интерпретаторы WebAssembly под .NET и JVM.

        –1
        Разве это не позволяет интерпретирующему использовать всю ту же JIT-компиляцию?
        JIT-компиляция замечательна, когда на неё есть ресурсы. У FGPA и большей части мобилок их нет. С WebAssembly во время AOT-компиляции можно сделать значительно более сложные и затратные компиляции, чем позволяют ограничения по времени и ресурсам при JIT. Аналогию можно провести с asm.js, который по сути есть AOT-скомпилированный Javascript. Или с LuaJIT, который, в пику названию, предлагает возможность распространять AOT-скомпилированные модули. WebAssembly — шаг дальше в том же направлении.

        JVM привязана больше к инфраструктуре, а не к языку. Были причины, почему Java в своё время не заняла нишу WebAssembly, несмотря на попытки. И воз поныне там же. Подробнее можно здесь.

        Java 9 не спасёт ситуацию?
        Нет. Например, вам нужно сделать исполняемые модули с исключительно математическими функциями. На WebAssembly вы можете сделать подмножество, которое умеет только в математику. С JVM придётся тянуть рантайм, вне зависимости от версии Java.

        Кстати, гуглятся интерпретаторы WebAssembly под .NET и JVM.
        Так точно. Байткод и интерпретатор для WebAssembly MVP очень простые, буквально за пару вечеров можно написать. Это ещё одна причина, почему у технологии есть все шансы развиться. Порог входа намного ниже, чем в большинство системных разработок. Вся сложность на уровне компиляторов и средств разработки. Мы взяли интерпретатор WABT из соображений портируемости: С/С++ достаточно просто запускается практически везде.

        Фича как раз в том, что собранные модули можно запускать на любом интерпретаторе любой конструкции. В том числе, нативном, браузерном, или построенном поверх JVM и .NET.
          0
          Были причины, почему Java в своё время не заняла нишу WebAssembly, несмотря на попытки.
          Причина, собственно, одна: Ларри сильно денег хотел.

          Все недостатки CLR/C# и JVM/Java можно было бы исправить — но только совместными усилиями. А их владельнцы хотели их полностью контролировать, «бить по рукам» всех конкуретном и «снимать сливки».

          В результате «сливок» никому не досталось, и подходы, основанные на JVM (а это не только апплеты — были и другие интересные идеи) и подходы, основанные на CRL (Silverlight и прочее) оказались выкинутыми «на свалку истории», а мы остались с JavaScript'ом и, вот теперь уже, пытаемся переизобрести всё в третий раз…

          Посмотрим, что выйдет…
            0
            Причина, собственно, одна: Ларри сильно денег хотел.

            Дело не в этом, всё это попросту не может быть альтернативой — ведь по-сути оно не отличается от js. Суть васма именно в том, чтобы не быть привязанным к какой-то платформе, языку — он на том и асм.

            В результате «сливок» никому не досталось, и подходы, основанные на JVM (а это не только апплеты — были и другие интересные идеи) и подходы, основанные на CRL (Silverlight и прочее) оказались выкинутыми «на свалку истории», а мы остались с JavaScript'ом и, вот теперь уже, пытаемся переизобрести всё в третий раз…

            Неверно, нигде и никак не переизобретаются все эти «идеи» — они умерли потому, что никому не нужны.

            Причина проста — снизу должно быть то, что может быть снизу. На лоулевел языке можно реализовать хайлевел, а вот наоборот нет. К языку без ГЦ может прикрутить ГЦ, а вот наоборот нет. Именно в этом проблема — жаваскрипт. Жава ничем не отличается от жаваскрипта в этом плане. И нет смысла менять шило на мыло.

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

            И причина, как я уже говорил, не в самой форме, а в том, что это более «совершенная форма». Никому не нужно по сети гонять текст, никому не нужен запрос-ответ, никому всё это не нужно. Вернее нужно тем, кто к этому привык, но это субъективные желания.

            Хочешь текст? Пожалуйста — бинарный проток это позволяет, а вот наоборот нет. Хочешь себе запрос-ответ — пожалуйста, всё это реализуется на базе более общего протокола.

            Именно в этом суть — более «совершенное» вытесняет менее совершенное и ограниченное, ведь ограничить что-то всегда можно, а вот расширить — нет.
              0
              К языку без ГЦ может прикрутить ГЦ, а вот наоборот нет.
              Если бы. Дело в том, что программирование в системе с ГЦ и без ГЦ — очень сильно разные вещи. При этом в системе с ГЦ можно программировать, как в системе без ГЦ — и это часто делается (кладём всё на массивы и «ручками» управляем из содержимым), а вот наоборот — фиг. Много вы видели систем на C++ с ГЦ? Не на «сбоку прилепленным» C# (Java, Lisp — нужное подчеркнуть), а на С++?

              Именно в этом суть — более «совершенное» вытесняет менее совершенное и ограниченное, ведь ограничить что-то всегда можно, а вот расширить — нет.
              Вопрос только в том, что вы понимаете под словом «совершенное». А то пока получается тавтология: если технология А вытесняет технологию Б, то технология А — более совершенна… возможно, но если мы об этом можем узнать только пост-фактум, то что это нам даёт?

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

              Если вы о «близкой к CPU» форме — то причём тут webasm? Для этого машинные коды есть…
                0
                Если бы. Дело в том, что программирование в системе с ГЦ и без ГЦ — очень сильно разные вещи.

                Идентичные.

                При этом в системе с ГЦ можно программировать, как в системе без ГЦ — и это часто делается (кладём всё на массивы и «ручками» управляем из содержимым)

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

                ГЦ от управляемого хипа отличается только одним. В управляем есть new и delete, а в ГЦ есть только new. ГЦ — является обычным куском рантайма, таким же как и любой malloc. Поэтому, в языке без ГЦ вы можете заменить malloc на ГЦ и использовать только new, а вот в языке с ГЦ — нет, у вас ниоткуда delete не родиться и ГЦ не вырубится.

                Много вы видели систем на C++ с ГЦ? Не на «сбоку прилепленным» C# (Java, Lisp — нужное подчеркнуть), а на С++?

                К С++ прикручивается ГЦ за 5минут, только это никому не нужно. И тут говориться не об этом — говориться о рантайме. Любой рантайм с ГЦ зависит от ГЦ, а ГЦ — это такой же рантайм, который так же зависит от ГЦ, а значит он существовать не может. Таким образом ГЦ может существовать только тогда, когда он и связанный с ним рантайм не зависит от ГЦ, а значит его написать на языке с ГЦ НЕВОЗМОЖНО.

                Вопрос только в том, что вы понимаете под словом «совершенное». А то пока получается тавтология: если технология А вытесняет технологию Б, то технология А — более совершенна… возможно, но если мы об этом можем узнать только пост-фактум, то что это нам даёт?

                Причём тут какие-то технологии? Причём тут какое-то вытеснение? Есть реальность, в рамках которой никакого ГЦ нет, а есть уже обёртка над этой реальность — ГЦ.

                Исходная форма — это всегда текст. Ну человеки, потому что, текст пока порождают.

                Человеки никого не интересуют. Вы даже не поняли того, что там написано. Исходная форма для asmjs — это не текст, а это было сказано в контексте asmjs.

                Если вы о «близкой к CPU» форме — то причём тут webasm?

                При том, что никакого текста в природе не существует — существует бинарь и только он, а текст — это уже его представление.

                Но текст никому не нужен сам по себе — текст, это представление данных в текстовой форме, что не является нативным для железяки, да и для программирования в целом. В рамках «близкой к CPU» форме числа не представляются как строки.

                Для этого машинные коды есть…

                Не для этого. Любая программа — это не только код, но и данные, да и сама программа — есть данные. А в рамках этих самих данных — существует некая структура.

                Структуру данных «текстом» вообще никак невозможно организовать, поэтому «текстовая структура» выкидывается.

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

                К тому же, в тексте имеются некоторые интерпретируемые, т.е. текстовое представление неких отдельных объектов — те же числа. И железяка умеет в числа, и если искомое число возможно представить в железяке, то оно требует конвертации, иначе — железяка с ним работать не может. Таким образом — текстовое представление чисел — не нативно.

                И такого масса, те же идентификаторы( из них код состоит на 80%+) — они так же могут иметь разное представление. И текстовые они — это так же «не нативно».

                Именно поэтому бинарь и является исходной формой, исходной для машины формой. И asm — это лишь рядовой представитель. И исходная она не только для команд, исполняемых cpu, но и для данных. А код является данными.

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

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

                Именно поэтому ненужны и текстовые форматы, и тут нет места рассуждениям о «а как же читаемость человека» — они попросту несостоятельны. Причины просты:

                Данные читает машина, которая не умеет в текст. Поэтому любая обработка текстовых форматов — есть to_binary | process | to_text, что попросту не имеет смысла.

                И раз этот самый to_text уже существует, а значит бинарное представление является полным( оно всегда может быть полным), то это to_text можно поставить перед to_text | human_process | to_binary, таким образом — мы обеспечиваем человека текстовым форматом.

                Это будет так же прозрачно, как и gzip. Очень смешно читать эти рассказы из комментов о том, «как же мне сложно будет читать tcpdump», только все эти комментаторы не знают, либо не хотят знать о том, что никакой текст по сети не гоняется — гоняется бинарь из-под gzip(подставь нужное).

                Именно в этом и смысл webasm. Мы убираем AST | to_text | to_binary | browser_exec. Зачем нам это абсолютно бесполезное to_text | to_binary, к тому же — это не просто текст — это «js».

                  0
                  ГЦ — является обычным куском рантайма, таким же как и любой malloc.
                  Серьёзно? Давайте сравним.

                  Проект A:
                  1. Библиотека K использует dlmalloc.
                  2. Библиотека L использует tcmalloc.
                  3. Библиотека M вообще под ARM и несёт ещё один tcmalloc.
                  Ничего страшного: ну чуть нерационально будет использоваться память. Ни один аллокатор ничего о других знать, в общем, не должен.

                  Проект B:
                  1. Библиотека X написана на С# и её рантайм несёт один GC (на самом деле несколько).
                  2. Библиотека Y написана на Java и её рантайм несёт другой GC.
                  3. Библиотека Z написана на Guile — и в ней есть ещё один GC.
                  Что будет если мы всё это соберём вместе и запустим? В лучшем случае эти GC будут «воевать» друг с другом и тратить в три раза больше ресурсов, чем один GC. Но до этого момента ещё дожить надо. Вначале у вас будет «кровь, кишки, расчлененка», пока вы не явно не подружите ваши GC. Причём каждый из них должен знать о всех других GC, которые у вас есть.

                  Поэтому, в языке без ГЦ вы можете заменить malloc на ГЦ и использовать только new, а вот в языке с ГЦ — нет, у вас ниоткуда delete не родиться и ГЦ не вырубится.
                  Причём тут вообще язык? Языков в системе может быть сколько угодно. Вопрос в наличии/отсутствии GC в системе. То, что у вас система позволяет запускать «произвольный» язык совершенно не обозначает, что вы «поверх этого» сможете реализовать GC. В PNaCl полноценный GC был невозможен, в ASM.js — теоретически возможен, но практически — крайне проблематичен.

                  К С++ прикручивается ГЦ за 5минут, только это никому не нужно.
                  Ну да, конечно, зелен виноград, ой как зелен. Вам не кажется что ситуация, когда сотни тысяч (или даже миллионы?) проектов обходятся без GC плохо совместима с подобными заявляениямии. Вот на Java — GC почему-то нужен «прям всем». Во вкрученном «внутрь» внушительной части этих проектов Python'е — GC тоже есть. Да даже в Objective C (который почти C, только «чуть лучше») GC был… раньше. А вот в C++ «это никому не нужно». Не странно ли это?

                  Таким образом ГЦ может существовать только тогда, когда он и связанный с ним рантайм не зависит от ГЦ, а значит его написать на языке с ГЦ НЕВОЗМОЖНО.
                  Вот даже так. А кто тут песни пел про то, что ГЦ является «обычным куском рантайма, таким же как и любой malloc»? Вы уж определитесь, пожалуйста. Malloc я могу спокойно писать на языке с malloc'ом, однако.

                  К сожалению на этом осмысленная часть рассуждения кончается, так как последующее словоблудие расшифровке не поддаётся, так что я ограничусь, пожалуй, обсуждением GC.
                    +1
                    Серьёзно? Давайте сравним.

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

                    Причём каждый из них должен знать о всех других GC, которые у вас есть.

                    Не должен. Это не из чего не следует, как из этого НИЧЕГО не следует.

                    Причём тут вообще язык? Языков в системе может быть сколько угодно. Вопрос в наличии/отсутствии GC в системе.

                    Никакого вопроса нет.

                    То, что у вас система позволяет запускать «произвольный» язык совершенно не обозначает, что вы «поверх этого» сможете реализовать GC.

                    К чему это и что это должно значить? Попытка слиться на эмуляцию? Нет, не получиться. Никому не интересно то, что «можно» запустить — всем интересно то, как это можно запустить, вернее то — что это даст. И под запустить имеется ввиду именно прямой запуск.

                    В PNaCl полноценный GC был невозможен, в ASM.js — теоретически возможен, но практически — крайне проблематичен.

                    И? Это проблемы PNaCl, а не ручного управления.

                    Ну да, конечно, зелен виноград, ой как зелен. Вам не кажется что ситуация, когда сотни тысяч (или даже миллионы?) проектов обходятся без GC плохо совместима с подобными заявляениямии.

                    Кто это должно знать и что из этого следует? Он им не нужен именно потому, что они без него жили и живут.

                    Вот на Java — GC почему-то нужен «прям всем».

                    Мир жава и мир С++ — это разные миры. Я не буду рассказывать об управляемости и производительности, но пойди там ораклу расскажите о том, что хотспот надо переписать на жаву и о том, что им нужен ГЦ.

                    Во вкрученном «внутрь» внушительной части этих проектов Python'е — GC тоже есть. Да даже в Objective C (который почти C, только «чуть лучше») GC был… раньше. А вот в C++ «это никому не нужно». Не странно ли это?

                    Нет. Сравнивать скриптуху и пускалки сишного/крестового рантайма с тем, на чём этот рантайм пишется — идиотская затея. Именно от того они и пускалки, что ни в каком ином назначении они не состоятельны.

                    Вот даже так. А кто тут песни пел про то, что ГЦ является «обычным куском рантайма, таким же как и любой malloc»? Вы уж определитесь, пожалуйста.

                    Поподробнее, где именно у меня тут противоречие? В чём мне надо определиться? Да, ГЦ обыкновенный кусок рантайма, и? Это как отменяет то, что реализация ГЦ на ГЦ рекурсивно зависит от ГЦ? Нет.

                    Malloc я могу спокойно писать на языке с malloc'ом, однако.

                    К чему это? И ГЦ можно писать на языке с ГЦ, и?

                    Суть в том, что языки( о которых я говорю) с маллоком никак от маллока не зависит, в отличии от языка с ГЦ. Если бы он зависел — была бы такая же рекурсивная зависимость.

                    Они работают с памятью напрямую и им маллок для этого не нужен. Маллок лишь некая абстракция, которая даёт и забирает куски памяти.

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

                    К сожалению на этом осмысленная часть рассуждения кончается, так как последующее словоблудие расшифровке не поддаётся, так что я ограничусь, пожалуй, обсуждением GC.

                    Слив засчитан. Кстати, что именно вы не смогли расшифровать и почему — вы ведь сможете мне показать и рассказать? А то, как я отличу «это словоблудие» от «мне нечего ответить — оправдаюсь тем, что безосновательно назову тезисы/аргументацию оппонента словоблудием»? Я должен вам поверить?

                      0
                      Я только совсем чуть-чуть, про GC. В С++ правит бал Rc (он же reference counting). В ObjC посмотрели на это дело и решили заменить GC на Rc, и прикрутить Arc как более простой вариант, чем умные указатели. Такой шаг со стороны Apple явно не говорит в пользу GC как парадигмы для управления памятью при системном программировании. Rc так же принят как основная парадигма памяти в Rust.

                      Есть и третья базовая парадигма управления памятью — MemPool. Её много в C, и немало в C++. В частности, на ней работает Apache HTTPD, очень много мелких парсеров вроде RapidJSON и специализированных библиотек вроде libtess.

                      Проблема GC как парадигмы в том, что она слишком универсальна. GC пытается решить абсолютно все проблемы с памятью за программиста. Это имеет свою цену. Rc и MemPool имеют довольно большой список ограничений и требуют строить архитектуру определённым образом, но в применении часто не сложнее GC. Загвоздка в том, что для Rc и MemPool нужно уметь грамотно проектировать системы. А это специфический навык, отличный от базовых навыков программирования. GC же позволяет запускать херово спроектированные системы так, чтобы они работали и не падали прямо сейчас. Пусть медленно и неэффективно, но работали.

                      Если человек взял такой инструмент, как С++, ему, скорее всего, нужно нечто, работающее эффективно. А это заведомо не про GC. И даже не потому, что сами реализации GC медленные, а потому, что парадигма GC не содержит в себе подсказок, как правильно спроектировать систему.

                      Лично я сторонник пулов памяти. Да, проектировать под них сложно. Зато это позволяет давать менее опытным разработчикам среду, которая в общем случае аналогична среде с GC по способу работы с ней, но значительно более эффективна.
                    0
                    Много вы видели систем на C++ с ГЦ?

                    Самый известный и красивый пример — Chromium, там он им реально помог и решил достаточно проблем.
                    chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/Source/platform/heap/BlinkGCAPIReference.md
            0

            Спасибо за ответы.


            JVM привязана больше к инфраструктуре, а не к языку. Были причины, почему Java в своё время не заняла нишу WebAssembly, несмотря на попытки. И воз поныне там же. Подробнее можно здесь.

            Да, песенка спета, да и к лучшему что так закончилось. Аплеты выкинут и целый груз с плеч.
            А вобще все эти нашпигованные платформы, лезущие в интернет — изобилуют дырами. Как флеш. Может с WebAssembly такого не будет

            • НЛО прилетело и опубликовало эту надпись здесь
                0

                --crate-type=cdylib — помогло от проблемы с main, спасибо. Исправил в статье.


                Проблемы с rust_begin_unwind в вашем примере нет, поскольку её убирает wasm-gc. Так же, как и кучу функций из std без #![no_std]. Собирать таким образом минимальный вариант для отладки не слишком рационально. Для релизной сборки, понятное дело, оптимизатор нужен, и он проблему решит.


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


                На самом деле, здесь есть два различных подхода. Первый подход — сделать полностью функциональную систему на wasm-модулях. В таком случае портирование libc — хороший вариант.


                Наш подход — сделать скриптовую песочницу на WebAssembly. Такую, чтобы в ней было крайне сложно прострелить себе ногу, и с настолько низким порогом входа, насколько возможно. А дизайн libc (если сравнивать, например, с CoreFoundation) добавляет свою весомую долю в базовую сложность языка. Не говоря о том, что это оверкил по функциональности.

                • НЛО прилетело и опубликовало эту надпись здесь
                    +1
                    Вы не поняли идею изначально. Не язык, а, скажем так, мета-API. С бекендом в виде wasm. И с фронтендом в виде любого языка, способного компилироваться в wasm. Для запуска специализированных модулей, скриптов, на простом интерпретаторе, без веб-окружения. Отсутствие веб-окружения сразу ломает emscrpten, который создаёт код, заточенный под веб-окружение (хотя там есть подвижки в сторону отдельных модулей).

                    Собственно, мнение, что это нафиг не нужно, как и нафиг не нужна архитектура wasm32-unknown-unknown в Rust уже высказано, прочитано и учтено. Сходу не найду, но в rust internals про это была не одна простыня.
                0

                Не надо забывать что webassembly появился как костыль для js.

                  0
                  А C++ и ObjectiveC как костыли к C. А С как костыль к B. Noted.
                  • НЛО прилетело и опубликовало эту надпись здесь
                      +1
                      Если инженерия софта будет конкурсом популярности — софт будет исключительно красиво падать.

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

                Самое читаемое