Pull to refresh

Comments 30

Смотрел недавно исходники LLVM и нашел там WebAssembly target, так что можно уже наверное писать код на C без Emscripten.
Интересно, я так понимаю данную технологию можно применять не только для повышения производительности, но и для обфускации кода JS. А обратное преобразование есть? Из байткода в JS (или в другой читабельный формат)?
А получится ли такой «фарш провернуть назад»? :)
Однозначно, да. Есть несколько инструментов для трансляции Байт кода jvm в исходный java код. Появление трансляторов wasm -> js вопрос времени.
Вернуть обратно в тот JS, который конвертировали в wasm — это можно, но зачем? Реальные-то исходники обычно на C/C++…
UFO just landed and posted this here
Получится, только вот если пере компиляцией кода в байт код, исходники обфусцировать, а потом скомпилировать, то при обратном процессе ты получишь очень не понятный код.
Для защиты кода — это как раз и хорошо.
Главный для меня вопрос, получается я смогу писать код для браузера на c#? И разор будет работать на клиенте? да целый asp.net получается можно вытащить на клиента, а сервер будет RESP api например + отдача загрузчика
Существуют трансляторы из C# в JS, так что вы можете попробовать уже сейчас, без WebAssembly. Но ваш скрипт будет тащить за собой реализацию BCL под JS — в лучшем случае, слинкуются только прямо или косвенно используемые части (которых все равно будет очень много), а худшем — вся стандартная библиотека целиком.

Если хотите получить нормальный, поддерживаемый результат — искренне советую использовать нативные инструменты и не превращать стек .NET в серебряную пулю. Попробуйте тот же Typescript — после C# он вполне привычный и удобный.
Вся хитрость в том, что вы считаете «лишним». Давайте для примера возьмем следующий код на C#:

Console.WriteLine("hello".StartsWith("hell"));

Идиоматическое решение на JS заняло бы также одну строчку:

console.log("hello".indexOf("hell") === 0);

Но автоматический транслятор так не работает. Он видит, что вы использовали метод StartsWith — значит в вашем приложении используется класс System.String, реализацию которого нужно перенести целиком. Открываем содержимое класса с помощью ILSpy и видим добрые две сотни методов! А если заглянуть внутрь некоторых, то увидим, что их реализация использует другие классы, например System.Convert, System.Text.Normalization, System.Text.StringBuilderCache, System.Globalization.CultureInfo. Их тоже нужно перенести, и их зависимости, и зависимости их зависимостей, и так далее.

Процесс определения зависимостей крайне трудоемок. Нет способа быстро определить, на какие классы ссылается определенный класс в ходе своей работы. Более того, при использовании рефлексии или даже Activator.CreateInstance это может быть вообще невозможно определить статически. Поэтому придется подтянуть следующую по размеру единицу разбиения кода, которая может работать автономно и для которой зависимости видны явно — сборку. В итоге, ваша одна строчка кода потребовала подтянуть за собой mscorlib целиком.

Невольно возникает вопрос — почему транслятор такой тупой? Мы же в 2016 году живем, у нас тут каждый второй — программист, работающий в коворкинге над стартапом по краудфандингу лэндингов, телефоны понимают голосовые команды, машины на автопилоте катаются — а написать идиоматичный код на JS нельзя? Да можно, конечно, но это потребует титанических усилий и никак не окупится. Изучить родные веб-технологии и переписать приложение на них все равно окажется проще.
Но автоматический транслятор так не работает. Он видит, что вы использовали метод StartsWith — значит в вашем приложении используется класс System.String, реализацию которого нужно перенести целиком. Открываем содержимое класса с помощью ILSpy и видим добрые две сотни методов!

Это неправда! Хороший вырезатель зависимостей работает совсем не так как вы думаете! Агрессивный dataflow-анализ способен творить чудеса.

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

Это правда. К сожалению, задача определения зависимостей плохо масштабируется, параллелится и плохо дружит с инкрементальной компиляцией. Тем не менее, процесс определения зависимостей нужен только для сборки production, там не сильно принципиально, что компилятор проработает минут 10 на CI-сервере. А во время разработки определять зависимости не обязательно.

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

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

а написать идиоматичный код на JS нельзя

А это и не требуется. Для программ на 10 строк вовсе не обязательно использовать трансляторы с «тяжёлых» языков вроде Java или C#. А для более серьёзных по объёму программ разница становится не слишком существенной.

Да можно, конечно, но это потребует титанических усилий и никак не окупится.

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

Изучить родные веб-технологии и переписать приложение на них все равно окажется проще.

Изучить родные веб-технологии действительно несложно, но тут есть другой фактор. Если у меня уже есть тонна кода для серверной части, которая при этом обвешана различными тулами для сборки проекта, статической проверки кода и т.д. то хотелось бы их по-максимуму переиспользовать для клиентского кода, а не выстраивать параллельно всю инфраструктуру фронтэнда с нуля. Да и частично переиспользовать сам серверный код на клиенте тоже очень приятно.
Это неправда! Хороший вырезатель зависимостей работает совсем не так как вы думаете! Агрессивный dataflow-анализ способен творить чудеса.

Хочется верить, что я действительно преувеличил и такие утилиты существуют, но среди бесплатных такого еще не встречал. Вышеупомянутый JSIL просто загружает целиковые сборки. Перспективный на первый взгляд Bridge.NET по факту подменяет стандартную библиотеку своей собственной частичной реализацией, и всё равно тащит за собой рантайм в размере 20к строк. Возможно, можно прогнать сгенерированный код через отдельные утилиты, но я не пробовал.
Если у меня уже есть тонна кода для серверной части, которая при этом обвешана различными тулами для сборки проекта, статической проверки кода и т.д. то хотелось бы их по-максимуму переиспользовать для клиентского кода, а не выстраивать параллельно всю инфраструктуру фронтэнда с нуля.

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

Про .NET не знаю, но для Java есть мой проект, который очень хорошо вырезает неиспользуемый код.

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

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

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

Транслятор (в моём случае) написан на Java, которая содержит баги, которая в свою очередь линкуется с glibc, который содержит баги и который запускается на Linux, который содержит баги и который запускается на железе, которое, представьте себе, тоже содержит баги.
TeaVM — крутая штука. Спасибо за ссылку, поставил звёздочку — возможно, когда-нибудь пригодится.

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

Транслятор (в моём случае) написан на Java, которая содержит баги, которая в свою очередь...
Вы правы, но не забывайте, что количество пользователей Java/glibc/Linux и конкретно взятого транслятора различаются на несколько порядков. Это влияет как на скорость (вероятность?) исправления багов, так и на шанс получить помощь в незнакомой ситуации.

Только что попробовал повозиться с упомянутым выше Bridge.NET чуть более подробно. Буквально за пару минут наткнулся на идеальный пример того, почему бы не стал использовать подобное решение в продакшене. Вот так у них реализован класс System.Uri:

// @source Uri.js

Bridge.define("System.Uri", {
    constructor: function (uriString) {
        this.absoluteUri = uriString;
    },

    getAbsoluteUri: function () {
        return this.absoluteUri;
    }
});

Вот как поступить в ситуации, если исходный код его использовал? Использовать свой велосипед вместо стандартного класса, патчить стандартную библиотеку транслятора, отправлять feature request и ждать у моря погоды? Ни одно из решений мне не кажется хорошим.
Мы уже год занимаемся выкидыванием похожей технологии из проекта и конца этому не видно.
Началось со здравой в общем-то идее — создадим структуры данных и модели на сервере, а для клиента — скомпилируем их же в JavaScript и придумаем «универсальный синхронизатор» который будет поддерживать данные в актуальном состоянии по обе стороны. Потом решили, что раз уже модели на C# — давайте и клиентский код на нем писать, благо bindings к jQuery шли с компилятором. А потом взяли нескольких фронтэндщиков, которые писали сразу на JS а чтобы не «отрываться от коллектива» — создавали заглушки на C# и вставляли в них свой код с помощью специальной аннотации. В результате получилась каша.
Для этого надо не только сделать компилятор C# кода в wasm (или преобразователь из MSIL), но и проехаться им по стандартной библиотеке .NET и библиотекам ASP.NET.
А потом завернуть это вместе со своим приложением и получить файл на много-много мегабайт.
Поэтому, как мне кажется, если и можно будет писать на C# (или Java), то только используя некоторое подмножество стандартной библиотеки.
.net core? Как я понимаю все компилируется заранее, лишнее вырезается. Так что клиент получает то, что ему надо.
Действительно, итоговый файл получится легче, но все равно огромным. net core не делает никакой магии, просто теперь базовая библиотека классов подключается по отдельным сборкам (смотря что нужно), а не поставляется на машину целиком. Однако если вы в коде где-то использовали System.Collections.Generic, то все равно придется в WebAssembly тащить его целиком.
Хм, Юнитевский IL2CPP режет код даже очень неплохо. ЧТо мешает макрософту сделать так же?
Есть различные техники, чтобы очень аккуратненько вырезать всё то, что ненужно. Мой проект использует такие техники, так что на выходе генерит достаточно маленький JS со всеми необходимым либами.

Конечно, всё это хорошо работает только в отсутствие reflection. Есть устоявшийся стереотип, что без reflection некоторые вещи написать невозможно. На самом деле, я разработал альтернативный механизм, на котором я успешно реализовал такие традиционно требующие reflection вещи, как сериализация/десериализация объектов в JSON и REST-клиент. Конечно, переиспользовать существующий код с reflection не получается, но всё равно, это гораздо лучше, чем TypeScript, в котором вообще нельзя переиспользовать код C#.

Правда, получается подмножество стандартной библиотеки, но оно достаточно большое, чтобы можно было писать вполне себе серьёзные приложения, и при этом получать достаточно маленькие JS-файлы.
Вот здесь http://cshtml5.com/#learn-more
пишут, что .NET Types and Framework Classes (45% supported)
Использовать технологию slim binaries в 2016 году, это, конечно круто, главное, не забывать, откуда всё пошло и что это такое. Читаем 7 Эффективный подход к переносимому коду в статье «Оберон с гаджетами...», 1999.
Ну и погуглить на тему этих самых slim binaries и имени Michael Franz, который, по-сути, и является автором сеё штуки.
Это я так, исторических основ и перспектив ради.
Чувствуется если оно таки выйдет в production на большинстве браузеров, JS как ЯП потеряет как минимум 50% аудитории.
И бешеная популярность сегодня обернется стремительным падением…
Немного классики по теме
https://www.destroyallsoftware.com/talks/the-birth-and-death-of-javascript
UFO just landed and posted this here
Есть какие-либо исследования, связанные с информационной безопасностью для WebAssembly?
Sign up to leave a comment.