Всем браузерам нужны киллер-фичи для завлечения. Можно удачно обыгрывать то обстоятельство, что основные как-то долго допетривают до ГОСТ TLS. С 2012го года 9 лет прошло, и всё не сделают
«Непрозрачные» веб-приложения, которые беспокоят пуристов, это — мелочь в сравнении с тем, что обещает нам WebAssembly. Речь идёт о выводе производительности веб-приложений, работающих в браузерной «песочнице», практически на уровень нативных приложений.
WebAssembly для этого много ещё не умеет.
Чтобы запустить истинный параллельный поток, нужно создать Wasm.Memory с параметром shared True, но сейчас требуется обязательно указание максимального размера памяти, то есть, заранее обозначен потолок роста.
Настоящий процессор, когда складывает 2 миллиарда с 2 миллиардами, отмечает в EFLAGS переполнение, и мы сразу идём бросать исключение. В WebAssembly EFLAGS теряется. А как жить-то, как жить без EFLAGS? Приходится изгаляться так:
AdaMagic/wasm/rtl.wasm/standard.h
/****************/
/* Unary negation and absolute value overflow only for the most-negative
number. */
#define s_32_neg_v(result, x) /* result = -x; */ \
if (((result) = -(x)) == S_FIRST) rts_overflow()
#define s_32_abs_v(result, x) /* result = abs(x); */ \
do { \
const int32 _xcopy = (x); \
if (_xcopy == S_FIRST) rts_overflow(); \
(result) = abs(_xcopy); \
} while (0)
/****************/
/* Signed addition and subtraction are implemented in terms of the
unsigned operations. Overflow is determined by comparing
the sign bits of the operands and result, which is done
using bit-wise xor. We first calculate the result (lower 32 bits)
and then check whether it overflowed. */
/* Addition overflows iff x and y have the same sign,
and the result has a different sign (from x and y). */
#define s_32_plus_v(result, x, y) /* result = x + y; */ \
do { \
const int32 _xcopy = (x); \
const int32 _ycopy = (y); \
const int32 _same_sign = ~_xcopy ^ _ycopy; \
/* The sign bit of _same_sign is set iff x and y have \
the same sign. */ \
(result) = _xcopy + _ycopy; \
if ((_same_sign & ((result) ^ _xcopy)) < 0) rts_overflow(); \
/* The sign bit of "((result) ^ _xcopy)" is set iff result and x have \
different signs. Overflow if that and _same_sign both have \
sign bits set. */ \
} while (0)
/****************/
/* Subtraction overflows iff x and y have different signs,
and the result and x have different signs. */
#define s_32_minus_v(result, x, y) /* result = x - y; */ \
do { \
const int32 _xcopy = (x); \
const int32 _ycopy = (y); \
const int32 _diff_sign = _xcopy ^ _ycopy; \
/* The sign bit of _diff_sign is set iff x and y have \
different signs. */ \
(result) = _xcopy - _ycopy; \
if ((_diff_sign & ((result) ^ _xcopy)) < 0) rts_overflow(); \
/* The sign bit of "((result) ^ _xcopy)" is set iff result and x have \
different signs. Overflow if that and _same_sign both have \
sign bits set. */ \
} while (0)
/****************/
/* For multiplication, we treat the various cases for y separately. We
check for overflow by checking whether x is in the right range. If one
operand is known at compile time, then the compiler should make that one
y, so the C compiler can hope to eliminate all but one range check, and
perform the divides at compile time. We need to take care to avoid
dividing by zero, and to avoid dividing the most-negative number by
minus one. */
#define s_32_times_v(result, x, y) /* result = x * y; */ \
do { \
const int32 _xcopy = (x); \
const int32 _ycopy = (y); \
\
if (_ycopy > 0) { \
rts_range_check(_xcopy, S_FIRST/_ycopy, S_LAST/_ycopy); \
} else if (_ycopy < -1) { \
rts_range_check(_xcopy, S_LAST/_ycopy, S_FIRST/_ycopy); \
} else if (_ycopy != 0) { \
/* The "-1" special case */ \
if (_xcopy == S_FIRST) rts_overflow(); \
} \
(result) = _xcopy * _ycopy; \
} while (0)
/****************/
/* Division can only overflow when dividing the most negative number by
-1. */
#define s_32_div_v(result, x, y) /* result = x / y; */ \
do { \
int32 _xcopy = (x); \
int32 _ycopy = (y); \
if (_xcopy == S_FIRST && _ycopy == -1) rts_overflow(); \
(result) = _xcopy/_ycopy; \
} while (0)
/****************/
Компилятор вынужден проштамповывать таким кодом каждую арифметическую операцию, иначе теряется фирменная адская безопасность.
Ах, да, если обнаружена лажа, нужно бросить исключение. Но в Wasm нет исключений. Родных. Можно зайти в JS, чтоб JS бросил исключение, тогда оно сдерёт весь стек Wasm и вылетит с другой стороны в вызывающий JS. И не сработают финализаторы! Ну такое.
Если мы хотим писать как на настоящем процессоре, нас такая лажа не устроит, мы хотим ещё и ловить эти исключения, и обрабатывать. И всякие ошибки роста памяти, обычно сдирающие стек Wasm, хотим ловить. И тут начинаются танцы на батуте (Trampolined Style) по типу Continuation Passing C. Так вот ты какой, «практически натив»!
Что ещё может натив? Может библиотеку загрузить динамически и в синхронном стиле. Существующие трансляторы Wasm это поддерживают довольно плохо. Ну вот что нужно сделать в обычном Wasm, чтоб произвести такую загрузку? Библиотека динамически загружаемая предоставляет какие-то, допустим, COM-подобные объекты. Если там не COM, а glib, погоды не меняет. Для косвенных вызовов в Wasm используются массивы функций с идентичной сигнатурой. Для каждой сигнатуры отдельный массив. Нужно массивы дополнить тем, что предоставляет библиотека. Вызывающих нужно связать с дополненными версиями всех массивов, чтоб они могли косвенно вызывать методы объектов, созданных новой библиотекой. Чтоб сама библиотека могла косвенно вызывать свои методы, ей нужно произвести релокацию: рассказать библиотеке, по каким смещениям в дополненных массивах начинаются добавленные ею методы, а потом в блобе сегмента данных пропатчить таблицы виртуальных методов.
Под Windows-то уже ASLR отработал, и несмотря на его работу, и достаточно рандомно получилось, и релоцированный слепок закешировался на диске. Ах да, диск. А зачем на диск? А мы же прямо с диска можем mmap сделать! У нас в нативе есть вирутальная память. А на WebAssembly фиг. У нас каждый байт Wasm.Memory стоит как настоящий. В нативе может применяться оптимистичное выделение памяти, почти моментальное, а потом по требованию выделяются настоящие страницы. В нативе библиотеки нередко прямо с диска шлёпаются релоцированные. Под стек место выделяется оптимистично. Почему стеком Wasm крайне сложно пользоваться, написано выше, но если им не пользоваться, то пользуемся сегментированным стеком в Wasm.Memory, где за каждый байт надо честно платить.
Это всё очень далеко от натива.
Многие компиляторы, которые я видел, поэтому генерят отнюдь не набор библиотек. Отнюдь! Вот берём мы, допустим, сайт типа ВК и видим, что он сделан на JS, и что JS там грузятся по требованию: для музыки, для альбомов, для вики грузится только когда понадобилось. Библиотеки кешируются и обновляются независимо. Нам втирают, что Wasm вроде как то же самое, но быстрее. Но когда мы берём многие реальные Wasm-трансляторы, они ведут себя совсем не так. Мы хотели такие же отдельные кешируемые независимо обновляемые библиотеки, а получили большой целиком обновляемый блоб, и из-за того, что обновляется он целиком, он ещё и обновляется часто. Минус кеш.
но как общий принцип кто не научился жить без трассирующей сборки мусора, тот идёт нафиг из технологического стека
А какова мотивация у такого принципа?
Не быть распоследним скотом, как те плохие парни, софтом которых мне приходилось пользоваться на первых работах, на отнюдь не топовых компах провинциального провайдера. И как те другие плохие парни, которым я доверился, поставил их софт, написал конвертер под формат вики, привязался, а как счёт количества объектов пошёл на какие-то смешные тысячи, так оно затормозило и пошло жрать электричество в вечном цикле.
Трассирующая сборка — это вечный двигатель наоборот. Ему всегда есть, чем заняться, и он этим занимается. Мне бы, пожалуйста, вечный двигатель нормальный, чтоб вырабатывал, а не потреблял. А если такого нет, то пусть не будет никакого. Настрадался.
Да и foreign export в хаскеле есть и вполне успешно работает.
Когда я думаю про интероп, у меня в голове образы WinRT, COM, OLE Automation, VirtualBox XPCOM, libobjc и отчасти SOM. С уже формально решёнными вопросами владения, освобождения ресурсов, уведомления об ошибках и наследования.
А FFI — это только первая ступень лестницы, по ней ещё шагать и шагать к высокоуровневому взаимодействию. Вот, допустим, на макосе есть Oxygene/Toffee, и взять бы написать на гипотетическом избавленном от трассирующей сборки мусора Хаскелле монаду Дейкстры, заполучить её в Oxygene как значение-последовательность (sequence of), и по этому значению походить средствами LINQ. Или в языке Ада, если генератором привязок спроецировать на тип с аспектом Default_Iterator, тоже comprehension можно устроить.
Моя подпись в письмах гласит: If you want to get to the top, you have to start at the bottom
Переходил с QBasic на Turbo Pascal, и там дорвался до ассемблерных вставок. Помню, изучал: вот есть mov для чисел, а есть stos и lods, s = «строковые» инструкции. Для чисел и для строк, видимо. Какой же был шок узнать, что процессору как муравью нужно всю строку облазить, чтоб что-то с ней сделать, и эти «строковые» инструкции не для всей строки, а для шажочка по ней.
Вот эти современности рискуют закамуфлировать ещё больше деталей
Осваивать его не придётся, он часть учебной программы JetBrains, но как общий принцип кто не научился жить без трассирующей сборки мусора, тот идёт нафиг из технологического стека. Как Haskell научится, так библиотеки на нём станет приемлемо использовать из других языков.
Из моей практики, циклы в структурах, о которых в первую очередь вспоминают, это ничтожная часть всех утечек.
Куда более распространенная в си ситуация связана с «беспорядочной половой жизнью» указателей и спонтанные, неформализованные и нигде не задокументированные контракты владения вида:
память освобождает вызывающий
память освобождает вызываемый
указатель нужно скопировать себе, передавать его как есть (работает как дескриптор)
содержимое указателя нужно скопировать себе, передавать копию по значению/указателю
память статическая, не копировать, ссылаться напрямую
и т.д.
Притом что во всех случаях интерфейс, утрируя, может выглядеть как void foo(void* ptr).
При таком подходе утечь память, прозевав, кто же все-таки должен ее прибирать, — раз плюнуть.
это одна из болезненных особенностей поддержки плюсового легаси. Рефакторишь на ссылки/смартпоинтеры и сразу дышится легче.
И если при рефакторинге для ссылок/умных указателей можно взять сразу комовские, то почему бы и нет, заодно и интероп.
Может быть, дело не в COM, а в ATL? Я иногда слышу жалобы на COM, и часто при этом всплывает какой-то ATL, наверное, одно с другим как-то коррелирует.
За что-либо путное надо платить деньги, а бесплатное, как правило, не стоит выеденного яйца.
Я не знаю ни одного реально практического примера, где была бы полезной технология COM
У вас часть кода на Аде, часть кода ещё на чём-то. Чем их сопрягать собираетесь?
Разновидности COM встречаются и под Mac OS. Ну не реестр там, по-другому было. Для Linux я видел и в p7zip автономный COM, и VirtualBox XPCOM с возможностью RPC.
Да неужели? Все вызовы простого COM — виртуальные, по смещению в таблице виртуальных методов. Таблиц виртуальных методов COM плодит немеряно, плюс, система ещё прокси генерит даже внутри процесса, для разных apartments. Поди разберись, чей седьмой метод хотят вызвать.
механизмы, которые сегодня используются, были созданы почти 22 года назад. Создание актуальной документации для такого длительного периода времени весьма сложная задача
Да прям там длительный период. COM 1995, DCOM 1996, вот и все основные события. 2 года, а потом внедрение. Это же не Swift, сменивший 5 ABI. COM+ нигде не видел в действии. Из интересного только OLE Automation и .NET интероп было, и потом надолго стабильность. Подвижки случились только в WinRT.
Учитывая, насколько плохо программисты осведомлены хотя бы о том, что есть, к каким-то подвижкам я бы и не призывал. Подвижки нужны в том, чтобы COM и VirtualBox XPCOM (под Linux) библиотеки делали почаще.
Никогда не видел столько агентов в одном месте. Столько перерыл, чтоб найти.
Покупо вроде бы даже с физлицами самозанятыми могут работать (но не все способы оплаты доступны). И Интернет-магазин прямо на их платформе можно сварганить и для физических, и для цифровых товаров.
А тем, кто всё же собрался покупать кассу, можно поискать скидки на ОФД тут, тут и тут
Что в 90х джава тормозила, что сейчас. Божатся, клянутся, что вот теперь-то мы точно сборщик мусора не тормозящий сделали. А воз и ныне там. Тормозит как чёрт знает что. Диспетчер задач откроешь, и сразу понятно, где у нас трассирующая сборка мусора.
В Delphi IDE, угорев по дотнету, добавили дотнетовские компоненты, и оно затормозило. Хорошо, что нашлись умельцы, сделали Delphi Lite, и оно не тормозит, потому что всё, что со сборкой мусора, вырезано. Я сделал вывод: хочешь, чтоб не тормозило — делай без сборки мусора. Только так.
20 лет кормят завтраками, надоело до чёртиков. Так и хочется сказать: ребятки, давайте вы там где-нибудь отдельно в своей песочнице самоубеждайтесь в быстроте трассирующего сборщика мусора, а мне как пользователю дайте старый добрый счётчик ссылок, раз уж не смогли придумать ничего лучше, чем написать программу на Джаве.
Кстати, для Java есть Javolution. Он не умеет инлайнить в JIT и прочее, но он быстр. Уж не связано ли это с тем, что там счётчик ссылок вместо трассировок по свопу?
Но Javolution не поставить так просто вместо java.exe. А было бы здорово, чтоб прямо java.exe ключики в командной строке прописать, и трассирующий сборщик мусора пошёл нафиг.
Всем браузерам нужны киллер-фичи для завлечения. Можно удачно обыгрывать то обстоятельство, что основные как-то долго допетривают до ГОСТ TLS. С 2012го года 9 лет прошло, и всё не сделают
WebAssembly для этого много ещё не умеет.
Чтобы запустить истинный параллельный поток, нужно создать Wasm.Memory с параметром shared True, но сейчас требуется обязательно указание максимального размера памяти, то есть, заранее обозначен потолок роста.
Настоящий процессор, когда складывает 2 миллиарда с 2 миллиардами, отмечает в EFLAGS переполнение, и мы сразу идём бросать исключение. В WebAssembly EFLAGS теряется. А как жить-то, как жить без EFLAGS? Приходится изгаляться так:
Компилятор вынужден проштамповывать таким кодом каждую арифметическую операцию, иначе теряется фирменная адская безопасность.
Ах, да, если обнаружена лажа, нужно бросить исключение. Но в Wasm нет исключений. Родных. Можно зайти в JS, чтоб JS бросил исключение, тогда оно сдерёт весь стек Wasm и вылетит с другой стороны в вызывающий JS. И не сработают финализаторы! Ну такое.
Если мы хотим писать как на настоящем процессоре, нас такая лажа не устроит, мы хотим ещё и ловить эти исключения, и обрабатывать. И всякие ошибки роста памяти, обычно сдирающие стек Wasm, хотим ловить. И тут начинаются танцы на батуте (Trampolined Style) по типу Continuation Passing C. Так вот ты какой, «практически натив»!
Что ещё может натив? Может библиотеку загрузить динамически и в синхронном стиле. Существующие трансляторы Wasm это поддерживают довольно плохо. Ну вот что нужно сделать в обычном Wasm, чтоб произвести такую загрузку? Библиотека динамически загружаемая предоставляет какие-то, допустим, COM-подобные объекты. Если там не COM, а glib, погоды не меняет. Для косвенных вызовов в Wasm используются массивы функций с идентичной сигнатурой. Для каждой сигнатуры отдельный массив. Нужно массивы дополнить тем, что предоставляет библиотека. Вызывающих нужно связать с дополненными версиями всех массивов, чтоб они могли косвенно вызывать методы объектов, созданных новой библиотекой. Чтоб сама библиотека могла косвенно вызывать свои методы, ей нужно произвести релокацию: рассказать библиотеке, по каким смещениям в дополненных массивах начинаются добавленные ею методы, а потом в блобе сегмента данных пропатчить таблицы виртуальных методов.
Под Windows-то уже ASLR отработал, и несмотря на его работу, и достаточно рандомно получилось, и релоцированный слепок закешировался на диске. Ах да, диск. А зачем на диск? А мы же прямо с диска можем mmap сделать! У нас в нативе есть вирутальная память. А на WebAssembly фиг. У нас каждый байт Wasm.Memory стоит как настоящий. В нативе может применяться оптимистичное выделение памяти, почти моментальное, а потом по требованию выделяются настоящие страницы. В нативе библиотеки нередко прямо с диска шлёпаются релоцированные. Под стек место выделяется оптимистично. Почему стеком Wasm крайне сложно пользоваться, написано выше, но если им не пользоваться, то пользуемся сегментированным стеком в Wasm.Memory, где за каждый байт надо честно платить.
Это всё очень далеко от натива.
Многие компиляторы, которые я видел, поэтому генерят отнюдь не набор библиотек. Отнюдь! Вот берём мы, допустим, сайт типа ВК и видим, что он сделан на JS, и что JS там грузятся по требованию: для музыки, для альбомов, для вики грузится только когда понадобилось. Библиотеки кешируются и обновляются независимо. Нам втирают, что Wasm вроде как то же самое, но быстрее. Но когда мы берём многие реальные Wasm-трансляторы, они ведут себя совсем не так. Мы хотели такие же отдельные кешируемые независимо обновляемые библиотеки, а получили большой целиком обновляемый блоб, и из-за того, что обновляется он целиком, он ещё и обновляется часто. Минус кеш.
Не быть распоследним скотом, как те плохие парни, софтом которых мне приходилось пользоваться на первых работах, на отнюдь не топовых компах провинциального провайдера. И как те другие плохие парни, которым я доверился, поставил их софт, написал конвертер под формат вики, привязался, а как счёт количества объектов пошёл на какие-то смешные тысячи, так оно затормозило и пошло жрать электричество в вечном цикле.
Трассирующая сборка — это вечный двигатель наоборот. Ему всегда есть, чем заняться, и он этим занимается. Мне бы, пожалуйста, вечный двигатель нормальный, чтоб вырабатывал, а не потреблял. А если такого нет, то пусть не будет никакого. Настрадался.
Когда я думаю про интероп, у меня в голове образы WinRT, COM, OLE Automation, VirtualBox XPCOM, libobjc и отчасти SOM. С уже формально решёнными вопросами владения, освобождения ресурсов, уведомления об ошибках и наследования.
А FFI — это только первая ступень лестницы, по ней ещё шагать и шагать к высокоуровневому взаимодействию. Вот, допустим, на макосе есть Oxygene/Toffee, и взять бы написать на гипотетическом избавленном от трассирующей сборки мусора Хаскелле монаду Дейкстры, заполучить её в Oxygene как значение-последовательность (sequence of), и по этому значению походить средствами LINQ. Или в языке Ада, если генератором привязок спроецировать на тип с аспектом Default_Iterator, тоже comprehension можно устроить.
Переходил с QBasic на Turbo Pascal, и там дорвался до ассемблерных вставок. Помню, изучал: вот есть mov для чисел, а есть stos и lods, s = «строковые» инструкции. Для чисел и для строк, видимо. Какой же был шок узнать, что процессору как муравью нужно всю строку облазить, чтоб что-то с ней сделать, и эти «строковые» инструкции не для всей строки, а для шажочка по ней.
Вот эти современности рискуют закамуфлировать ещё больше деталей
И если при рефакторинге для ссылок/умных указателей можно взять сразу комовские, то почему бы и нет, заодно и интероп.
Может быть, дело не в COM, а в ATL? Я иногда слышу жалобы на COM, и часто при этом всплывает какой-то ATL, наверное, одно с другим как-то коррелирует.
Ну и что есть путного за деньги?
И что там трудоёмкого? Берём и клепаем интерфейс за интерфейсом
У вас часть кода на Аде, часть кода ещё на чём-то. Чем их сопрягать собираетесь?
Разновидности COM встречаются и под Mac OS. Ну не реестр там, по-другому было. Для Linux я видел и в p7zip автономный COM, и VirtualBox XPCOM с возможностью RPC.
Да неужели? Все вызовы простого COM — виртуальные, по смещению в таблице виртуальных методов. Таблиц виртуальных методов COM плодит немеряно, плюс, система ещё прокси генерит даже внутри процесса, для разных apartments. Поди разберись, чей седьмой метод хотят вызвать.
Да прям там длительный период. COM 1995, DCOM 1996, вот и все основные события. 2 года, а потом внедрение. Это же не Swift, сменивший 5 ABI. COM+ нигде не видел в действии. Из интересного только OLE Automation и .NET интероп было, и потом надолго стабильность. Подвижки случились только в WinRT.
Учитывая, насколько плохо программисты осведомлены хотя бы о том, что есть, к каким-то подвижкам я бы и не призывал. Подвижки нужны в том, чтобы COM и VirtualBox XPCOM (под Linux) библиотеки делали почаще.
Была ли в этом множестве Ада?
Для разработки BioShock 4 нанимали специалистов по открытому миру.
Интересующиеся этой темой собираются на канале GothenX
pokupo.ru/online-kassa
arsenalpay.ru/cashbox.html
robokassa.com/robokassa/robocheck
Никогда не видел столько агентов в одном месте. Столько перерыл, чтоб найти.
Покупо вроде бы даже с физлицами самозанятыми могут работать (но не все способы оплаты доступны). И Интернет-магазин прямо на их платформе можно сварганить и для физических, и для цифровых товаров.
А тем, кто всё же собрался покупать кассу, можно поискать скидки на ОФД тут, тут и тут
В Delphi IDE, угорев по дотнету, добавили дотнетовские компоненты, и оно затормозило. Хорошо, что нашлись умельцы, сделали Delphi Lite, и оно не тормозит, потому что всё, что со сборкой мусора, вырезано. Я сделал вывод: хочешь, чтоб не тормозило — делай без сборки мусора. Только так.
20 лет кормят завтраками, надоело до чёртиков. Так и хочется сказать: ребятки, давайте вы там где-нибудь отдельно в своей песочнице самоубеждайтесь в быстроте трассирующего сборщика мусора, а мне как пользователю дайте старый добрый счётчик ссылок, раз уж не смогли придумать ничего лучше, чем написать программу на Джаве.
Кстати, для Java есть Javolution. Он не умеет инлайнить в JIT и прочее, но он быстр. Уж не связано ли это с тем, что там счётчик ссылок вместо трассировок по свопу?
Но Javolution не поставить так просто вместо java.exe. А было бы здорово, чтоб прямо java.exe ключики в командной строке прописать, и трассирующий сборщик мусора пошёл нафиг.