Новый этап в гонке скоростей JavaScript. Модуль OdinMonkey ускоряет низкоуровневый код в 10 раз

    Модуль OdinMonkey — часть движка IonMonkey, отвечающая за оптимизацию и компиляцию низкоуровневого Asm.js — 21 марта был включён в состав сборки Firefox Nightly. Что такое Asm.js? — это подмножество языка JavaScript, позволяющее программировать «на уровне ассемблера» — без динамической типизации и выделения памяти. В каком-то смысле Asm.js аналогичен технологии Google Native Client, только с обратной совместимостью — код, написанный по спецификации Asm.js, является корректным кодом JavaScript и будет выполняться на любом движке, только медленнее, чем при наличии OdinMonkey.

    Asm.js позволяет в ряде случаев вплотную приблизиться к производительности нативного кода — программа на Си, скомпилированная в Asm.js, обычно работает всего вдвое медленнее оригинала:



    Asm.js использует для указания типов редко используемые конструкции языка, наподобие "|0". Они подобраны так, чтобы не влиять на семантику выражений стандартного JavaScript, именно благодаря этому код Asm.js заработает в любом браузере уже сегодня, а завтра, если в нём появится поддержка «ассемблера JavaScript», просто начнёт выполняться раз в 10 быстрее. Вот пример кода на Asm.js:

    function foo(x, y) {
       var x = x|0;   // x имеет тип int
        var y = +y;    // y имеет тип double
        return +(x * y);   // функция возвращает double
    }
    


    Стандарт Asm.js и модуль OdinMonkey прежде всего обязаны своим существованием Люку Вагнеру, автору Emscripten — популярного компилятора из LLVM в JavaScript, который не раз упоминался на Хабре. Код, генерируемый этим компилятором, стал основой спецификации Asm.js. Кстати, ответы на часто задаваемые вопросы про Asm.js недавно перевёл хабраюзер Mithgol.

    В данный момент OdinMonkey можно включить только в Firefox Nightly на платформах x86/x64 под десктопными ОС Windows и Linux, вскоре должна появиться поддержка MacOS X и ARM. Для включения надо установить флаг javascript.options.​experimental_asmjs в about:config. Так как Asm.js в первую очередь предназначен для автоматической генерации компиляторами, писать на нём код вручную не слишком удобно. В будущем команда Mozilla рассчитывает добавить поддержку более эргономичного низкоуровневого синтаксиса, например на основе Low-Level JavaScript.

    Чтобы поближе познакомиться с Asm.js, можно начать с этой презентации и этой статьи. А продолжить можно, изучая официальную спецификацию.

    Поделиться публикацией
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 83
    • +90
      Костыли конечно знатные.
      • –3
        Позиционируется:
        «как писать на js чтобы было быстро и язык не менялся»
        Является:
        «как писать на очередном диалекте js, который мы теперь тоже поддерживаем»
        • +5
          «как писать на js чтобы было быстро и язык не менялся» — писать вы можете на C/C++:
          Asm.js в первую очередь предназначен для автоматической генерации компиляторами


          «как писать на очередном диалекте js, который мы теперь тоже поддерживаем» — это не диалект, а подмножество языка:
          код, написанный по спецификации Asm.js, является корректным кодом JavaScript и будет выполняться на любом движке
          • –5
            Я всегда полагал, что диалект это и есть подмножество/ответвление языка.

            Предлагаю задуматься над тем, зачем вообще нужен asm.js. На мой взгляд чтобы javascript в браузере быстро работал. И именно javascript, так как у нас есть уже огромное количество кода на нем и нам нужно его оптимизировать. То есть что бы не думали авторы о предназначении asm.js, использоваться он будет именно теми, кто пишет на js, а не теми кому в шутку хочется что-то портировать на js.
            Это нисколько не умаляет достоинств asm.js, равно как и не делает написание кода на C/C++ полезным, с учетом того что он будет портирован в js.
            • +4
              Не знаю, как насчёт точности словарного определения, но для меня диалект — это то, что не совместимо, но похоже по синтаксису. Например — CoffeScript — диалект. Без компилятора код CoffeScript просто не может быть проинтерпретирован. А Asm.js — может.

              Что до вашего второго тезиса — использование двух и более языков в одном проекте — обычное дело в программировании. Может быть в каком-то идеальном мире можно написать всё с начала до конца на одном языке, а в реальности — пишем ядро на Си (иногда с ассемблерными вставками, кстати), интерфейс на Питоне, и ещё плюс скрипты на каком-нибудь Lua. Так и здесь — пишем приложение на js, критичные части переписываем на C.
          • +27
            Позиционирование более похоже на «как скомпилировать программу в JavaScript для достижения кросс-платформенного выполнения во браузере со скоростью не более чем в два раза меньшей по сравнению с родным кодом». Что по сути позволяет программисту гораздо меньше трахаться со сборкою (потому что достаточно собрать один раз), а также это открывает новую светлую страницу в книжке о кросс-компилировании в целом. (В настоящее-то время легко ли, сидя на Linux, собирать модули под Windows? А наоборот?)

            Но это только первая ласточка.

            По-настоящему шарахнет, когда движок V8 (известный в качестве довольно шустрого) применит аналогичную оптимизацию, то есть начнёт исполнять asm.js (или иной близко аналогичный диалект джаваскрипта) со страшной, непреоборимой скоростью. Потому что на V8 основан движок Node.js — и тогда пред очами изумлённого мира ярко вспыхнет светоч очередного WORA-движка (от слов «Write once, run anywhere», изначально это был лозунг Sun про Java), но движок этот станет разительно отличаться от всех предыдущих, во-первых, по скорости (потому что V8 и asm.js), а во-вторых, по гибкости: не будет ни малейшей необходимости сочинять только на одном специальном языке — ни на Java (как это было в случае с Sun), ни на asm.js, ни даже только на JavaScript, потому что число языков, в JavaScript компилируемых, весьма значительно, и даже один только Emscripten (автор которого породил asm.js) позволил скомпилировать движки Python, Ruby, Lua, не говоря уж о том, что сам Emscripten является средством для преобразования в JavaScript итогов работы LLVM, а LLVM, в свою очередь, воспринимает ActionScript, Ada, D, Fortran, GLSL, Haskell, байткод Java, Objective-C, Python, Ruby, Rust, Scala и C#.

            Будущее будет лучезарным.
            • +1
              Хех, будущее наступит скорее, если поставщики браузеров договорятся и предоставят единую виртуальную машину языка низкого уровня. И вот тогда да — пиши однажны, используй везде. А до этого момента пиши однажды, портируй всегда =)
              • +2
                А зачем единая машина? Например, есть Node.js и что же, разве там исполняется какой-то другой JavaScript, не такой, как во браузерах? Меж тем виртуальные машины в общем случае различны. (Например, в Файерфоксе — IonMonkey, а во Хроме и в Node.js — V8.)

                У меня даже есть наглядный пример, близкий событиям вокруг Emscripten и поэтому asm.js. Как известно, одним из наиболее зрелищных примеров работы Emscripten является сборка SQLite. И что же? Во браузере она работает (в каждом из современных браузеров, хотя виртуальная машина в них далеко не единая). Но и в Node.js также работает! (Есть даже проект, основанный на этом модуле.) Работает, однако же, не без проблем, но это проблемы не SQLite, а атомарного доступа к файловой системе изнутри Node.
                • +3
                  Ну как зачем? Чем ниже уровень инструкций, тем ближе результат к желаемому, независимо от языка.

                  Что же до «равного» исполнения js — во Файерфоксе, например, нет концепции скрытых классов, которая есть в V8. То есть язык один, код один, а исполняется по-разному (имеется ввиду скорость, не результат выполнения). И для оптимальной работы писать нужно тоже по-разному.
                  В то же время, если бы у нас была одна VM с одним набором инструкций — то автоматически важным становится только транслятор (с любого исходного языка на общепринятый конечный байт-код), а не браузер, исполняющий код.
                  • +1
                    Согласен в целом. Но это уже слишком лучезарно, чтобы сбыться. А так если задуматься, то абсолютно логично писать клиентскую часть на том языке, каком ты считаешь нужным, стыковать клиентскую и серверную часть без лишних костылей, не ждать когда поставщики браузеров запилят более современный диалект javascript, а просто скачать свеженькую версию компилятора своего любимого языка в «межбраузерный байт-код» и наслаждаться жизнью.
                  • +7
                    во браузерах?

                    Как? В обозревателях же! Что ж вы язык рожной англицизмами поганите?!
                    • 0
                      Вообще-то в вéбниках, но об этом — отдельная блогозапись.
                      • +1
                        Русский термин такой русский.
                        • 0
                          Русскость повысилась за счёт перехода на русский способ словообразования («-ник» вместо «-er»), удобство употребления возросло за счёт краткости (всего два слога, тогда как в слове «браузер» их три, а в слове «обозреватель» — пять).

                          Не идеал ли достигнут? Можно ли улучшить этот результат?

                          Можно было бы дополнительно улучшить одно из этих двух качеств, но только за счёт ухудшения другого (и наоборот), а зачем это.
                          • 0
                            Тогда уже сетевик… а то вебник как-то не до конца по-русски
                            • –3
                              Когда я дал гиперссылку на ту блогозапись, в которой рассматривалось то моё предложение, то имел в виду и возможность нынешним читателям ознакомиться с тогдашними высказанными там комментариями. Вариант «сетевик» был рассмотрен вон в том комментарии 11 апреля 2012 года и аргументированно отвергнут мною.
                              • 0
                                Ну тогда может быть «Глобальносетевик»? Или если поностальгировать (от слова «ностальгия», а не «понос») по советским номенклатурным традициям, то что-то вроде ПСДИ (Программное Средство Доступа в Интернет). К примеру, ПСДИ Хром-25 — звучит вполне себе в духе.
                                • +2
                                  ПСДИ для русского уха несколько неблагозвучно.
                                  Есть в этой аббревиатуре что-то от Патрульного Инспектора Дорожного Регулирования.
                                  • 0
                                    Вы нарочно доводите до абсурда, я за Вами это ещё в мае прошлого года заметил.

                                    Пожалуйста, ПСДИте в другом месте.
                                    • 0
                                      Простите, если задел…
                                • +2
                                  неее, сетевик — это нетник. Вебник — это паутинник.
                                  • 0
                                    Веб — имя собственное, оно не переводится.
                                    • 0
                                      А браузер тогда зачем переводить если «веб» нельзя? Как то тут взаимоисключающими параграфами попахивает.
                                      • 0
                                        В контексте Word Wide Web последнее слово не значит «паутина», это нечто вроде нашего «БСЭ», но сленгового. Может «Всемирная Матчасть».
                                • +7
                                  Кому удобство? Трафик экономить?
                                  Слово — это не просто набор букв. Слово «браузер» имеет четкую семантику, от слова 'browse' — просматривать. Что означает «вебник»? Нечто, связанное с вебом? Это слово может означать что угодно, начиная от сетевой карты, кончая человеком, зависимым от интернета.
                                  Может не надо устраивать фарс и предлагать какой-то суржик вместо устоявшегося термина?
                                  • +3
                                    Слово «рефрижератор» имеет чёткую семантику, от слова «refrigerate» — охлаждать, замораживать. Что означает «холодильник»? Нечто, связанное с холодом? Это слово может означать что угодно, начиная от змеевика с фреоном и кончая человеком, лопатою подкидывающим лёд. Может, не надо устраивать фарс?
                                    • 0
                                      Только, если отсылаться к to refrigerate, то холодильник называют a fridge. К данному слову применимы те же вопросы.
                                      • 0
                                        Слово «холодильник» в русском языке — сокращение от «холодильный шкаф».
                                        • +1
                                          Слово «будильник» в русском языке — сокращение от «будильный аппарат». (А слово «приёмник» — сокращение от «приёмный аппарат».)

                                          Слово «паяльник» в русском языке — сокращение от «паяльный инструмент». (А слово «напильник» — сокращение от «напильный инструмент». А слово «пробойник» — сокращение от «пробойный инструмент».)

                                          Слово «матюгальник» в русском языке — сокращение от «матюгальный мегафон».

                                          Слово «светильник» в русском языке — сокращение от «осветительный прибор».

                                          Слово «учебник» в русском языке — сокращение от «учебный материал». (А слово «задачник» — сокращение от «задачный материал».)

                                          Слово «треугольник» в русском языке — сокращение от «треугольная фигура».

                                          Слово «курятник» в русском языке — сокращение от «курятный сарай».

                                          Слово «внедорожник» в русском языке — сокращение от «внедорожный автомобиль».

                                          Слово «запальник» в русском языке — сокращение от «запальный механизм».

                                          Слово «подрамник» в русском языке — сокращение от «подрамный держатель».

                                          Слово «обменник» в русском языке — сокращение от «обменный пункт». (А слово «файлообменник» — сокращение от «файлообменный сайт».)

                                          Слово «чайник» в русском языке — сокращение от «чайная утварь».

                                          Слово «пододеяльник» в русском языке — сокращение от «пододеяльный утеплитель».

                                          Если нравится Вам эта стройная теория о том, что все слова, суффиксом «-ник» образуемые, являются на самом деле сокращениями — ради Бога; но тогда думайте, что слово «вебник» является сокращением от «вебный облазыватель», и тем невозбранно уложите его в ту же теорию.
                                          • 0
                                            В ответ уместно процитировать ваш-же коммент чуть выше:
                                            >Вы нарочно доводите до абсурда, я за Вами это ещё в мае прошлого года заметил.
                                            >
                                            >Пожалуйста, ПСДИте в другом месте.

                                            Как можно заметить, сами вы доводить до абсурда не гнушаетесь.

                                            Как бы вам ни хотелось, новые слова так не вводятся. Не нужно никому такое слово. А тем более, если это замена текущего технического термина. Технические термины должны быть понятны *всем*, чтобы более эффективно обмениваться знаниями. Хотите развивать язык — пишите художественные книги, а не повышайте «русскость» в комментах.
                                            • 0
                                              Большая часть слов из вашего списка никогда не употреблялась в разговорной речи в полном варианте.
                                              А «холодильный шкаф» — употреблялся.

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


                                              Илья Ильф, Евгений Петров. Одноэтажная Америка
                                          • 0
                                            Холодильник холодит, охлаждает (продукты). А вебник вебает?
                                            • 0
                                              Словарит или энциклопедничает.
                                    • +8
                                      Моя незабвенная преподавательница по ОССО однажды сказала:

                                      — «Фаерволл»? Зачем использовать англицизмы? Есть же прекрасное русское слово: «брандмауэр».
                                      • +2
                                        Оно, конечно, тоже заимствованное, но всё-таки ещё с XIX века, и уже успело прижиться.
                                        • 0
                                          С одной стороны, успело.

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

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

                              • +3
                                Хочу убежать подальше из этого лучезарного будущего. Почему не сделать нормальную виртуальную машину, а не эти костыли?
                                • +4
                                  1. Обратная совместимость со старыми браузерами.
                                  2. Очевидно, что производители браузеров не смогут договориться о единой виртуальной машине. Посмотрите на ситуацию с поддержкой аудио-видео кодеков в браузерах.
                                  3. Google делает Native Client, но кроме Google Chrome его никто не поддерживает — он не используется повсеместно, поэтому производители других браузеров просто игнорируют его существование. asm.js можно будет использовать уже сегодня, и это будет работать во всех браузерах. Разница будет только в производительности. Если использование asm.js станет популярным, производители браузеров будут вынуждены добавить его поддержку для повышения производительности такого кода.
                                  • 0
                                    Ну в целом после её повсеместного внедрения уже можно будет, наверное, превратить её в настоящую виртуальную машину. Но мой перфекционизм просто кричит от боли!
                                    • 0
                                      VEG
                                      3. Google уже рассматривает возможность использовать asm в Chrome.
                                    • +7
                                      Рассказываю: если сделать нормальную виртуальную машину, то всё работать будет только в альтернативном лучезарном будущем и только у тех, у кого эта машина установлена.

                                      А так будет работать у всех и будет работать прямо сейчас. Только медленнее. (Причём на уровне «немножко медленнее», а не на уровне «убейте меня, зачем мучаете?». Разница менее чем на порядок.)

                                      И так как состояние «виртуальная машина работает» куда привлекательнее состояния «виртуальная машина нормальная, но заработает только через несколько лет», то имеем то, что имеем.
                                    • –1
                                      Можно подумать, поддержка asm.js ускорит V8 в той же мере, что и *Monkey. Эдак мы и обычный ASM (который без js) перегоним? А количество языков… Как ни крути, но скорость порта Java -> LLVM -> asm.js будет куда ниже, чем просто Java. С другими языками аналогично.
                                      • +2
                                        не будет ни малейшей необходимости сочинять только на одном специальном языке — ни на Java (как это было в случае с Sun)
                                        А кто вам сказал, что виртуальные машины Java исполняют только код, написаный на Java?
                                    • 0
                                      Я правильно понимаю, что для подобного ускорения нужно будет все свои скрипты переписывать вручную под asm.js?
                                      • +1
                                        Можно под Asm.js, если там совсем мало или хочется поковыряться из любопытства, а можно — на C/C++, а потом скомпилировать в JavaScript. В Firefox Nightly будет летать, в остальных браузерах — просто работать.
                                        • +1
                                          Если верить статье, то не «просто работать» а «только медленнее»
                                          • +2
                                            Медленнее, чем в ночном фаерфоксе.
                                        • +2
                                          Как я понял из презентации, суть скорее не в том, чтобы писать прямо на asm.js, а писать на статитически типизированных языках и транслировать на него, сейчас основные успехи с С/C++.
                                          Statically-typed languages and especially C/C++ can be compiled effectively to JavaScript
                                          • 0
                                            Хм. То бишь взять тот же zlib и легко и просто его перенести на яваскрипт?
                                            • +12
                                              Да, притом они уже это сделали, чтобы проверить производительность. В статье есть табличка

                                                           odin (now)  odin (next)   sm       v8
                                              zlib         2.02         1.61         5.15    5.95
                                              

                                              Числа показывают во сколько раз полученный код исполняется медленнее скомпилированного через gcc с флагом O2 (1.0 будет означал бы ту же скорость).
                                              • 0
                                                Даешь конкурента Node.js!
                                            • 0
                                              Отлично, значит с C# тоже можно будет.
                                          • +2
                                            наверное TypedScript можно будет скрестить с asm.js
                                            • +1
                                              У asm.js только один большой минус, — не поддерживается строковый тип. Если бы поддерживался, это была бы революция.
                                          • +1
                                            Эмс, это что предлагаю писать js на С, компилить через asm.js что бы код быстрее работал аж в Firefox Nightly и то, если отдельно включить там OdinMonkey?
                                            Просветите в чем смылс?
                                            Для избранных которые будут ставить Firefox Nightly+OdinMonkey можно на С прогу написать, а все остальные разницы не заметят.
                                            Да и код такой поддерживать и дебажить явно сложнее обычно JS.
                                            Или я что-то не так понял?
                                            • +6
                                              Как я только что (одновременно с Вами) огласил чуть выше, перед нами первая ласточка.

                                              Во-первых, Firefox Nightly является отправною точкою шестинедельного цикла разработки: через шесть недель он превратится в Firefox Aurora, ещё через шесть — в Firefox Beta, а ещё через шесть — в реальный Mozilla Firefox, один из наиболее популярных браузеров Интернета. Поддержка asm.js будет доставлена многим миллионам реальных людей по всему миру, а не только горстке энтузиастов, употребляющих еженощные сборки.

                                              Во-вторых, есть надежда на то, что остальные браузеропроизводители подхватят эту движуху, и тогда величина аудитории asm.js превзойдёт всякое воображение.
                                              • +7
                                                Или вместо того, чтобы подхватить эту идею они выдумают каждый свой велосипед, подхватят его и начнется новый виток войны браузерных стандартов… Уж в ком я не сомневаюсь — так это в Микрософте. Уж они-то точно выдумают Js# какой-нибудь.
                                            • +3
                                              Ну вот захотите вы написать онлайн-оптимизатор изображений. Но при этом вы хотите делать все вычисления на клиенте, чтобы не загружать сервер. Берём исходники pngquant, компилируем в js — и все дела. Со временем asm.js будет поддерживаться в Firefox по умолчанию. А если фишкой будут пользоваться, и Firefox будет уделывать в таких скриптах другие браузера, думаю и остальные начнут поддерживать asm.js со временем. В результате — у пользователей изображения на вашей страничке будут оптимизироваться достаточно быстро, при этом сервер не будет нагружен этими вычислениями.
                                              • +2
                                                А со временем можно будет и биткоины майнить в браузере пользователя без спроса…
                                                • +2
                                                  Так это и сейчас можно, только медленно :)
                                                  • 0
                                                    Сразу возникла идея новой пирамиды. Регистрируемся в пирамиде… и все. Чтобы получать деньги, надо просто держать страницу браузера открытой. Больше страниц — больше денег.

                                                    Ушел смотреть, наверняка уже кто-то сделал такое…
                                                    • 0
                                                      Ставим прозрачную флешку на страницу 1x1px и используем портированный через алхимию майнер, можно даже скинуть часть работы на видеокарту.
                                                      • 0
                                                        Да уже года 2 как сделали. Реализации на java есть, и даже где то я сайт видел подобный.
                                                        Были попытки на javascript написанные, и они некоторое время работали.

                                                        В принципе ничего сложного там нет, исходники биткоин клиента доступны — портировать не проблема.
                                                        Мозги разминал, писал, знаю :)
                                                    • +1
                                                      Эффективнее это будет сделать на RiverTrail aka Parallel.js (вычисления на GPU) который, кстати, уже включен в FF Nighty. И, как ни странно, имеет обратную совместимость c однопоточным и процессорным JavaScript.
                                                • +5
                                                  Ого, и это всего Один Манки! А если два?
                                                • +1
                                                  редко используемые конструкции языка, наподобие "|0"

                                                  Используется как integer cast в каждом втором скрипте, чего она редкая-то.
                                                  • 0
                                                    На позапрошлой неделе рассказ о ней получил трёхзначный рейтинг на Хабрахабре — так что, наверное, всё же не общеизвестною была конструкция эта.
                                                  • +2
                                                    OdinMonkey в поле воин
                                                  • +2
                                                    Даешь программирование в машинных кодах для браузера! Это же сколько возможностей откроется.
                                                    • 0
                                                      В машинных кодах какого процессора?
                                                      • 0
                                                        На DCPU-16 конечно!
                                                        • 0
                                                          Всех, под которые портирован браузер.
                                                      • 0
                                                        Софтварный рендеринг в «2d» контексте будет гораздо быстрее :)
                                                        • +12
                                                          asm.js имеет очень ограниченный user-case и хорош только для написания молотилок цифр. Для многих их нас от него не будет ни горячо ни холодно. Однако же используя AOT компиляцию это даст существенный прирост в скорости рассчета физики в играх, адовы алгоритмы вроде Дугласа-Пекера и вычисление любого хэша. Притом, что функция, написанная, с asm.js будет работать быстрее из-за строгой типизации на бинарном уровне в любом браузере. В итоге выигрывают все!
                                                          • +2
                                                            Ну, расчёты используются много где. Уже есть «тяжёлые» для уровня браузера приложения вроде PDF.js. Казалось бы простая задача вроде обработки картинок тоже заметно требует ресурсов. Особенно обработка и сохранение. Например, mail.ru обрабатывает загружаемые картинки на клиенте, снижая трафик (не грузятся все мегабайты мегапикселей с мыльниц) и нагрузку на свои сервера. Наверняка, выиграет множество онлайн-приложений, которые могут быть не нужны достаточно часто, чтобы ставить специальные программы, но требоваться время от времени.
                                                          • 0
                                                            А я всегда так кодил на javascript — как на ассемблере!
                                                            • 0
                                                              Интересно быол бы посмотреть на онлайн-стрелялку на asm.js

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