Pull to refresh
75
-1
Alexey Andreev @konsoletyper

Пользователь

Send message

У кода на любом языке, скомпилированного в WASM всё-таки эффективность
(и в плане размера, и в плане производительности) будет гораздо лучше,
чем у того же кода, транспилированного в JS.

А вот и нет

Ещё причина в том, что порой хочется написать про то, что делаешь на работе, а из чисто внутреннего контекста это сложно выдрать. Вот например, делаю я сейчас UI-фреймворк для игрового движка. Игровой движок проприетарный, используется чисто внутри компании для разработки внутренних продуктов. И вот для меня персональная гордость - движок стилей а-ля CSS. Там целый ворох нетривиальных технических решений, чтобы это быстро работало на больших таблицах стилей (300+ селекторов) и на больших UI (10K+ view) и в том числе, инкрементальные апдейты - это когда вы поменяли класс где-то глубоко в иерархии view или что-то небольшое добавили в уже гигансткое дерево view, и стили пересчитались не за 100 мс, и даже не за 10 - счёт идёт на микросекунды. Ну и вот как всё это расписать для внешней публики? Для этого нужно вначале взять и написать такой же UI-фреймворк в опенсорсе, а зачем и кто за это будет за это платить? А выложить уже готовый движок в опенсорс мешает руководство.

Да, такие возможности есть, но это работает только в случае, если приложение написано целиком на Kotlin. Если же это Kotlin + Java, то спасает только native image или другие подобные AOT-компиляторы. Честно, я не в курсе, что сейчас творится на этом рынке, когда-то ещё были MOE, RoboVM и Avian, здравствуют ли они поныне - я не проверял.

Есть ещё один юзкейс для graal native image: компиляция приложений под iOS. Иногда в этом есть смысл, если хочется на Java/Kotlin ваять кроссплатформенно, но нативный look&feel вообще не нужен (например, игры).

Что касается неудобств с reflection, то тут есть одно решение: не использовать. Вы не поверите, на что способны annotation processor в умелых руках, дополненных compile time инструментацией байт-кода. Хотя полагаю, что, для spring boot это может быть невозможно.

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

Кстати, для junit 4 можно писать раннеры, которые тестовые классы загружают в кастомном лоадере, что может быть очень удобно при тестировании генераторов. Увы, в 5-м авторы перемудрили с системой расширений и такая возможность пропала.

Сколько там людей на планете понимает как c2 работает

Ну зачем же c2? Я про javac, kotlinc, scalac и иже с ними. c2 - это уже уровнем пониже и немного другие скилы.

Тут я пас. javac наше все. Код на сервере.

Так AOT-компиляторы обычно берут байт-код, там перед AOT-компилятором старый-добрый javac.

С чем угодно они уже довольно работают.

Вы про java.lang.reflect.Proxy? Не поддерживают.

Вот конкретно этот пример - не уверен, не пробовал. Если взять из моего примера генерацию байт-кода класса, сохранить его в виде класса с расширением class и прилинковать к проекту - класс загрузится. Какой бы ни был внутри android формат классов, SDK умеет переводить байт-код JVM в свой собственный формат. Не вижу причин, почему бы нельзя было в ClassLoader поддержать прозрачную трансляцию из байт-кода JVM в собственный формат - это должно быть тривиально. Боюсь только, что Android такой сгенерированный на лету байт-код будет интерпретировать или если сконвертирует в нативный код, то с минимальным числом оптимизаций.

Что касается моего личного опыта, то я использую на своём текущем проекте самописные генерялки байт-кода для нужд сериализации данных, RPC и привязки данных к OT. Но работают они в compile time.

Главное чтобы это на собеседованиях спрашивать не начали, блин.

Проекты проектам рознь. Где-то понимать, как генерируют байт-код JVM - это первейший необходимый навык. В компиляторных командах, например.

Прокси, лямбды и все такое что я перечислил

Прокси, как я уже написал, плохо работают с AOT-компиляторами и proguard/r8. Постоянно приходится думать, а не придётся ли мне после написания или рефакторинга очередной пачки кода завайтлистить ещё каких классов, чтобы приложение не упало. Можно всё то же самое сделать через кодогенерацию. Обычно всё же генерируют исходники через annotation processors, но бывают нюансы.

Ну и кстати, прокси работают только с интерфейсами, а не с абстрактными классами.

Если вам надо лезть в байт код, например для оптимизации, то пора переписывать код на плюсы

Это смотря какого рода оптимизации. Если есть алгоритм, который раз и навсегда написан, то да, это кейс. Если же пользователь что-то вводит и это что-то надо максимально быстро исполнить для разных входных данных (собственно, игрушечный проект в статье - намёк на такой кейс), то я лучше сгенерю байт-код Java, чем напишу на C++ генератор нативного кода. Пример: различные пользовательские скрипты. Да, в 90% случаев проще прикрутить что-то стандартное вроде JS, но бывает всякое. Ну например, представьте, что вы пишете Excel-подобную штуку и пользователь хочет (а он 100% хочет), чтобы формулы пересчитывались максимально быстро.

Плюс JNI имеет достаточно большие накладные расходы. И нативный код не инлайнится.

У всех свой продакшен. Мы вот используем и рады. Да и потом, если не все генерируют байт-код в продакшене, мало ли что. Где-то что-то не срослось и приходится смотреть глазами вывод `javap -c`. Или где-то заглючил спринг или хибернейт и сгенерил какую-нибудь обёртку, не проходящую валидацию. Так что понимать, как устроен байт-код - очень полезный навык, а для этого хорошо поупражняться таким способом.

Кстати, а можете привести конкретные доводы, почему именно "нет ни одного повода"?

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

Поиск по словам j2cl дал только вот эту issue, которая ещё не закрыта. Можно ссылку на новость или на документацию по поддержке WebAssembly в j2cl?

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

Ну так и в TeaVM тогда несложно привнести

С каких это пор j2cl поддерживает WebAssembly?

Насчёт стека, как я понял, проблема в том, что JVM стековая VM, а WASM регистровая

Неправильно поняли. Это вообще не проблема. TeaVM работает в SSA. Читайте внимательно.

Насчёт проверок на null, наверняка можно провести анализ графа исполнения и убрать часть проверок (нет смысла проверять локальную переменную на null, если мы уже проверили её до этого и не меняли).

Я так и делаю. Но на практике всё равно остаётся весьма много ситуаций, когда ничего про значение сказать нельзя.

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

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

Посмотрите на минимальный размер объекта в Java. Там у каждого объекта есть помимо vtable ещё и monitor, который не нужен в однопоточном wasm.

WebAssembly вполне себе многопоточный. Кроме того, TeaVM поддерживает потоки с помощью green threads. Так что ссылку на monitor приходится тащить. И за счёт различных ухищрений в TeaVM размер заголовка всего 8 байт. Меня совсем не устраивает, что WebAssembly добавляет ещё.

просто поместив данные vtable после структуры GC, компилятор же знает её длину.

И как же это должно выглядеть? И почему это должно помочь?

если отойти от дословного перевода джавы в WASM, а проводить статический анализ и делать эквивалентные преобразования кода

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

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

Нет никакого "байт-кода V8". V8 внутри себя использует IR, и даже не один, но никакого стандартного кросс-браузерного способа его сгенерировать нет. Я про генерацию JS. Собственно, раз уж у меня получилось генерировать вполне эффективный JS из байт-кода JVM, то не вижу никаких причин, почему нельзя было бы аналогичную задачу решить для CIL. Так вот, если я правильно понимаю, blazor берёт CIL и генерирует wasm. Интересно, а в MS пробовали генерировать JS? Где-то есть в публичном доступе сравнения размера/производительности и тулинга?

Судя по всему, там тоже нет необходимых классов из java.security. И нет java.util.zip

А впрочем, нет, TeaVM не подойдёт. Я смотрю, у вас там криптография, а TeaVM криптографию не поддерживает.

Изначально да, задумывался для компиляции C++, хотя и у C++ были проблемы, например, с теми же исключениями. Забавно было смотреть, какой огород они городят для обхода данного небольшого ограничения. Забавно смотреть, как они реализуют ссылки на локальные переменные с упомянутым в статье shadow stack.

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

Information

Rating
Does not participate
Location
München, Bayern, Германия
Date of birth
Registered
Activity

Specialization

Specialist
Senior
From 6,000 €
Java
Compilers
Kotlin
Gradle