← All posts tagged asmjs

В продолжение #2806882 , всё-таки, мне кажется, asyncify не все возможности задействовал. Должен быть какой-то компромиссный вариант, чтоб не сильно тормозило, но и не было интерпретатора.
breaking them up and so forth
by expanding the loop, two more async calls are introduced, such that more callback functions will be produced during the asyncify transformation
Вот, может быть, можно процедуры как-то аккуратненько ломать, чтоб не в 10 раз раздувались. switch и goto поставить в начале, и пусть будет соответствие 1:1.

Экспериментирую с AdaMagic и emcc. За основу взят rtl.windows. Все скомпилированные файлы пришлось выкинуть, так как это не LLVM биткод. Настроил в %ADA_MAGIC%\SITE\config по аналогии:
be_exec_name = C:\Program Files\Emscripten\emscripten\1.35.0\emcc
linker_exec_name = C:\Program Files\Emscripten\emscripten\1.35.0\emcc
Выкинуть пришлось
be_required_flag = -mno-cygwin
linker_required_flag = -mno-cygwin

Перекомпиляция адского RTL запускается так:
cd C:\GNAT\AdaMagic-2016-07-22\AdaMagic\windows\rtl.emscripten
adacgen -ke -ga src\.bdy src\.spc
del *.tmp.bc

Результаты:
Total: 325 files compiled. 287 successful, 38 unsuccessful.
Те, что unsuccessful, содержат всякие платформозависимые штучки, их портировать надо вручную или обойтись без них. И ещё там есть несколько чисто сишных исходников. Надо ещё с этим поэкспериментировать. Может, за основу лучше rtl.linux взять? В Linux вместо kernel32 glibc, а в emscripten, предположительно, для libc аналоги функций будет проще найти, чем для kernel32.

Поизучал предмет. Необходимость возврата управления, по видимому, невероятно серьёзная проблема. Есть emterpreter, но он не годится для интерпретации «всего», а только в режиме «белого списка», как в DOSBox. Но хорошо, что в emscripten есть способ относительно прозрачно сочетать emterpreter с обычным исполнением.

Неприятно было посмотреть, как сделана интеграция C++ с JavaScript. Главным образом — потому что там одиночные ссылки на объекты, а из–за бардака со счётчиками ссылок нет единого решения. Как я понял, научить любой конкретной реализации можно, но это уже получается не из коробки. Вот берём Objetive-C, и он уже лет 20 как со счётчиком ссылок для всех объектов, и любой потребитель/производитель знает, как делать этот подсчёт, а берём C++ — и там бардак, и берём WebIDL binder, и получаем интерфейс, где на объекты должна быть только одна сильная ссылка. Я на такое насмотрелся в Delphi, и мне это сильно не понравилось. Особенно тот момент, когда в Delphi 2009 или около сделали возможность заворачивать исключения в исключения, а чтоб завёрнутое исключение не уничтожилось, ему надо сделать AcquireException, то есть, у нас в одном языке появилось два способа подсчёта ссылок, один у TInterfacedObject, другой у Exception. А для многих объектов внятного управления памятью не было, и память замечательно текла, если программист что–то не рассчитал, положил в какой–нибудь TStrings, который счётчик ссылок не дёргает by design, и забыл. Или TComponentList, который тоже счётчик ссылок не дёргает, а сразу прибивает. Ещё раз такую петрушку наблюдать не хочется, пусть лучше сразу будет счётчик ссылок. Просто и понятно.

Objective-C в emscripten, к сожалению, не поддерживается. А так бы взять libdispatch, взять Reactive Extensions для Objective-C и что–нибудь бы получилось. Но нет. Пока там только геморрой.

При всей геморройности asm.js интересный. Если делать новый компилятор и заложить в нём поддержку этой платформы, это могло бы поспособствовать распространению.

Ada/Em — компилятор/интерпретатор на базе Ada/Ed
Ada/Ed — это компилятор/интерпретатор Ada 83, самый первый, прошедший проверку на соответствие стандарту по тестам Ada Compiler Validation Suite на IBM PC. Так как это интерпретатор, а Ada мыслится как язык, прежде всего компилируемый в машинные коды, да и стандарт хотелось бы не меньше 95–го, то долгое время до него почти никому не было дела, и в июле 2012 его сорцы (на C) выложили в открытый доступ.
Предъистория вопроса: есть у нас доступный в куче браузеров и этим интересный JavaScript, но вот есть у него один большой недостаток: надо время от времени возвращать управление. Программисту, чтобы не свихнуться, проще писать в синхронном стиле, а браузер выполняет только асинхронный код. Это решается часто просто использованием CPS (continuation-passing style). Теоретически можно любую синхронную программу переделать в асинхронную с помощью CPS. Везде, где я смотрел, это сделано руками, как–то все уже попривыкли. Но есть и парсеры/трансляторы, такие, как Wind.js, которые автоматически могут разрезать синхронную программу по швам и превратить в асинхронную CPS–лапшу.
Далее, вот есть у нас Asm.js, чрезвычайно оптимизируемое подмножество JavaScript. Если браузер поддерживает Asm.js и распознал специально помеченный кусок JavaScript кода как соответствующий всем требованиям модуль Asm.js, то генерируется быстрый машинный код. Однако, при написании программ, транслируемых в быстрый машинный код, есть один недостаток. Да всё тот же. Необходимость время от времени возвращать управление на самый верх, к браузеру. Через стек функций, через обработчики исключений — на самый верх. И тоже есть автоматические способы разпилить программу по швам и превратить в лапшу, но не CPS. Wind.js тут сработает, но требования Asm.js будут нарушены применением CPS, зато для Asm.js есть свой аналог: asincify. На его странице так и написано:
Другие возможные реализации
Closures (ломают asm.js)
Далее, читаем сравнение с asincify на странице emterpreter:
ASYNCIFY has a bad worst-case of large code size: If it needs to modify many methods, it can grow code size very significantly (even 10x more was seen).То есть, подход asyncify может настолько значительно раздувать код, что становится оправданным применение интерпретатора emterpreter.
Далее, читаем статью Почему мобильные web–приложения медленные. Одна из главных идей — не пользоваться сборщиком мусора, особенно в мобильных приложениях. Применительно к JavaScript это значит — применять Asm.js, а не обычный JavaScript, который безальтернативно со сборщиком мусора.
Вот именно такого сравнения не видел, но, когда смотрю на графики в статье, напрашивается предположение, что код, работающий на интерпретаторе в Asm.js, может работать даже быстрее, чем его CPS–аналог на JavaScript, за счёт того, что не вызывает сборку мусора так часто.
И в этот момент мы вспоминаем, что старый забытый Ada/Ed как раз уже устроен таким способом, который, так уж вышло, наилучший для браузеров. Написан на C, интерпретируемый. Так как в MS-DOS не было потоков операционной системы, Ada/Ed приходится содержать в своём составе многозадачный планировщик. В #2785610 я всё думал, где бы мне многозадачный планировщик для Asm.js взять. Вот, нашёл!
Так что берём Ada/Ed, компилируем его интерпретатор или даже компилятор emscripten, и вот она — радость! Пишем код для браузера в синхронном стиле, не сходим с ума от CPS–лапши, и с учётом архитектуры браузеров, работает это наилучшим образом, даже на мобильных устройствах. Для полного счастья нам понадобится мост между emterpreter и интерпретатором Ada/Ed. А то, что получилось, так и напрашивается быть названным Ada/Em.

forge.open-do.org
Недавно заметил, что там уже лежит в сорцах LLVM компилятор ParaSail. Точнее, он перегоняет байткод в инструкции LLVM, а байткод генерят компиляторы всех 4х экспериментальных языков, то есть, и Sparkel (Ада–подобный), и Parython (Python–подобный), и Javallel (Java–подобный), и ParaSail, который помесь всех трёх.
Однако, вчитавшись в последние посты по сабжу, увидел такое:
parasail-programming-language.blogspot.ru
At first we thought the built-ins needed to be translated to llvm code to successfully link with our generated llvm. To accomplish this, we used a tool called AdaMagic to convert the Ada source code (in which the built-ins are currently written) and Ada's run time system (RTS) to C source code then used the llvm C front-end "clang" to compile the rest of the way. Clang complained with hundreds of warnings, but, it worked. We were able to print integers, floats, and characters! We couldn't do much more with the built-ins at the time because we didn't yet have type descriptors working (see below).

After all the effort and dealing with the messy generated C code, we found out that the system linker could link object files compiled with the llvm backend called "llc" together with object files produced by the GNAT Ada compiler with no problem. That was a relief, as we really didn't want to go mucking around in the generated C code more than we had to.
Я–то хотел попускать зелёные потоки в web, да ещё в asm.js. А теперь вижу, что сами зелёные потоки скомпилировать в Asm.JS можно, а библиотеку времени выполнения — нет. Впрочем, подумав ещё немного, решил, что оно и не нужно. Поток там, считай, один, это уже немного менять рантайм. Ну или, если с WebWorkers, то, наверное, можно больше потоков, но тогда будет нужна коммуникация, которой в библиотеке для натива всё равно нет.

Наверное, если бы я этим занимался, я бы как–нибудь вообще обошёлся без LLVM, с одним только интерпретатором, зато прикрутил бы стандартный сетевой стек, JSON и XML, и портанул бы мои сетевые быдлоскрипты с node.js на нечто более человеческое и привычное. А если, так уж получилось, есть компиляция в LLVM, то всё это надо двинуть в UI и наладить взаимодействие между зелёными потоками клиентов и сервера. Есть предположение, что AdaCore не хотят пускать язык в массы пока он не устаканился, а создание компилятора в натив — это один из тестов, по результатам которого в языке могут что–то поменять.