<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>WebAssembly</title>
		<link>https://webassembly.su/</link>
		<description>Блог</description>
		<lastBuildDate>Wed, 11 Dec 2024 16:52:55 GMT</lastBuildDate>
		<generator>uCoz Web-Service</generator>
		<atom:link href="https://webassembly.su/blog/rss" rel="self" type="application/rss+xml" />
		
		<item>
			<title>Полиморфизм в языках программирования</title>
			<description>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/19883148.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s19883148.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;На тему разных языков программирования написаны разные книги. И &lt;a href=&quot;https://www.ozon.ru/product/yazyki-programmirovaniya-kontseptsii-i-printsipy-kaufman-vitaliy-shahnovich-elektronnaya-kniga-932634070/&quot;&gt;классика В.Ш. Кауфмана&lt;/a&gt;, и Glynn Winskel. Но если бы попросили выделить отличия языков программирования, то как бы на этот вопрос ответил автор? И автор бы начал с описания&amp;nbsp;кватернионов. Что известно про комплексные и гиперкомплексные числа?&lt;/p&gt;

&lt;p&gt;...</description>
			<content:encoded>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/19883148.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s19883148.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;На тему разных языков программирования написаны разные книги. И &lt;a href=&quot;https://www.ozon.ru/product/yazyki-programmirovaniya-kontseptsii-i-printsipy-kaufman-vitaliy-shahnovich-elektronnaya-kniga-932634070/&quot;&gt;классика В.Ш. Кауфмана&lt;/a&gt;, и Glynn Winskel. Но если бы попросили выделить отличия языков программирования, то как бы на этот вопрос ответил автор? И автор бы начал с описания&amp;nbsp;кватернионов. Что известно про комплексные и гиперкомплексные числа?&lt;/p&gt;

&lt;p&gt;$CUT$&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;У вещественных чисел есть линейный порядок. У комплексных чисел линейного порядка уже нет.&lt;/li&gt;
 &lt;li&gt;Умножение комплексных&amp;nbsp;чисел&amp;nbsp;коммутативно. Умножение кватернионов некоммутативно.&lt;/li&gt;
 &lt;li&gt;Умножение кватернионов ассоциативно. Умножение седенионов не ассоциативно, но альтернативно.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Видно, как по мере усложнения структуры теряются свойства. Усложнение структуры можно далее называть&amp;nbsp;&amp;laquo;Синтезом&amp;raquo;, а способность алгебраической системы быть проанализированной можно назвать&amp;nbsp;&amp;laquo;Анализом&amp;raquo;. Синтез и Анализ, &amp;mdash; альфа и омега языков программирования.&lt;/p&gt;

&lt;p&gt;Что можно сказать про соотношение Синтеза и Анализа?&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;Больше Синтеза, &amp;rarr; обычно меньше Анализа&lt;/li&gt;
 &lt;li&gt;Меньше Синтеза,&amp;nbsp;&amp;rarr; вовсе не факт, что больше Анализа&lt;/li&gt;
 &lt;li&gt;Анализ на заказ&amp;nbsp;обычно&amp;nbsp;просто не выполним. Интересный Анализ открывают, а не заказывают&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Например, по теореме Адамса существуют только четыре расслоения&amp;nbsp;Хопфа. Спорадических групп 26 (с группой Титса 27).&lt;/p&gt;

&lt;p&gt;Если захотеть заказывать Анализ, может просто ничего не получиться. Ну захотим гиперкомплексные числа размерности три, математики разведут руками. Можно поупрямствовать. Можно каждое ненулевое тройное число разложить на радиус и направление, и определить умножение тройных чисел как умножение радиусов отдельно, а для направлений использовать правило параллелограмма на сфере. Получается алгебра без особенно интересных свойств.&lt;/p&gt;

&lt;p&gt;Так и в устройстве языков программирования. Анализируемые свойства растут из структуры. Можно проиграть сразу на двух фронтах, и Синтез завалить, и в обмен на заваленный Синтез так и не получить никакого интересного Анализа. И ещё не получается потребовать Анализ на заказ. Как общий принцип, делается какое-то открытие анализируемой структуры, и этот Анализ цементируется в языке программирования, и исходя из зацементированного Анализа, программисту выдаётся доза Синтеза, не идущая вразрез с выбранной дозой Анализа, и потом доза Синтеза по возможности увеличивается, но пределы очерчены изначально. Увеличение Синтеза, не идущее вразрез с Анализом, &amp;mdash; это обычно синтаксический сахар, всё больше и больше синтаксического сахара, впрочем, и сам синтаксический сахар тоже не вполне полезен для Анализа, ведь исходные тексты могут быть подвергнуты Анализу со стороны разного инструментария, и новый синтаксический сахар сразу их все ломает, если только нет общепринятого промежуточного представления.&lt;/p&gt;

&lt;h1&gt;Структуры для полиморфизма&lt;/h1&gt;

&lt;p&gt;Сделав такое введение, можно рассматривать полиморфизм в языках программирования. Всё растёт из структуры. А структуры не заказываются, структуры открываются.&lt;/p&gt;

&lt;p&gt;Какие структуры в языке программирования могут отвечать за полиморфизм? Это:&lt;/p&gt;

&lt;ul&gt;
 &lt;li&gt;структура ссылки&lt;/li&gt;
 &lt;li&gt;структура нечто по ссылке&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Под ссылкой имеются в виду даже и такие сущности, как параметры методов. Ведь нужно же вызывать методы. У метода должен быть какой-то формальный тип параметра. А передаётся значение какого-то актуального типа. От системы&amp;nbsp;типов ожидается, что значение вызывающей стороны состыкуется с ожиданиями вызываемой стороны. Возможность стыковки определяется совместимостью на двоичном уровне, а совместимость на двоичном уровне, &amp;mdash; это уже Анализ. Тот самый Анализ, который не бывает на заказ, а бывает только как открытие, и проистекает из Синтеза структуры. Даже если язык программирования не в машинных кодах, эти принципы действуют. Не претендуя на новые открытия, перечислим варианты устройства ссылки и нечто по ссылке.&lt;/p&gt;

&lt;h2&gt;Структура ссылки&lt;/h2&gt;

&lt;p&gt;И здесь известные интересные варианты:&lt;/p&gt;

&lt;ol&gt;
 &lt;li&gt;вообще не указатель, а непосредственно содержимое&lt;/li&gt;
 &lt;li&gt;один указатель&lt;/li&gt;
 &lt;li&gt;два указателя&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;В контексте полиморфизма 1, как в языке&amp;nbsp;программирования Ада. generic. И generic в Delphi. И template в С++.&lt;/p&gt;

&lt;p&gt;Один указатель, &amp;mdash; тоже частый вариант. Можно встретить в COM,&amp;nbsp;Delphi interface и Objective-C. В других языках программирования можно воплотить, но отложим это до рассмотрения структуры нечто по ссылке.&lt;/p&gt;

&lt;p&gt;Два указателя, &amp;mdash; вариант реже, но встречаемый. Это Rust. В&amp;nbsp;других языках программирования можно это встретить для ссылки на отдельный метод. В Delphi есть синтаксис of object, объявляющий двойной указатель. В Objective-C нет явного типа, но популярна передача ссылки на объект и селектора к нему для подписки на событие.&lt;/p&gt;

&lt;p&gt;Трудность с двумя указателями в том, что в процессорах есть инструкция DCAS, двойного сравнения и замены, и если указателей уже и так два, то весь DCAS придётся тратить на одну двойную ссылку, а две двойных ссылки не получится покрыть DCAS. Не в любом процессоре есть DCAS, но всё же часто сейчас можно ожидать, что есть. В линейке x86 инструкция cmpxchg8b появилась в Pentium, и с тех пор DCAS вроде бы как долго был доступен. Когда происходил переход с Intel x86 на AMD 64, новые процессоры ставились в старые слоты материнской платы. И тут получалось, что материнская плата, чипсет, и вот это всё, оно может только CAS для 8 байт, а для 64 битов это одиночный CAS, а не двойной, и двойного снова нет, пока не обновить материнскую плату. В 2024 можно посчитать, что трудное детство компьютеростроения всё-таки позади, и всё-таки теперь и в 64 битах есть DCAS.&amp;nbsp;cmpxchg16b. Но всё ещё нет&amp;nbsp;cmpxchg32b и, наверное, и не будет.&lt;/p&gt;

&lt;h2&gt;Структура нечто по указателю&lt;/h2&gt;

&lt;ol&gt;
 &lt;li&gt;Произвольная&lt;/li&gt;
 &lt;li&gt;Одиночно наследуемая&amp;nbsp;VMT&lt;/li&gt;
 &lt;li&gt;Динамическое разрешение метода&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Известные комбинации структуры того и другого&lt;/h2&gt;

&lt;h3&gt;Ada generic, Delphi template, C++ template&lt;/h3&gt;

&lt;p&gt;Ссылка вообще не указатель, а собственно содержимое. Как правило, это требует повторной генерации кода для каждого варианта. И код для каждого отдельного варианта, может быть, по отдельности и быстр, но если копий кода много, то все копии не влезают в кеш, а код, не влезающий в кеш, это медленный код.&lt;/p&gt;

&lt;h3&gt;COM interface, взгляд со стороны&amp;nbsp;Delphi хакера&lt;/h3&gt;

&lt;p&gt;Ссылка из одного указателя, а сразу по указателю одиночная VMT. Отличительной особенностью является то, что на один и тот же объект могут быть разные указатели. Слабая &amp;laquo;идентичность&amp;raquo;. Хотя, если запросить IUnknown, то обычно через любой интерфейс можно получить одну и ту же ссылку на IUnknown. Кстати, запрос интерфейса здесь работает как &amp;laquo;динамическое разрешение метода&amp;raquo;, только запрашивается сразу пачка. Но так как это не является основным способом вызвать метод, то далее ограничения как для одиночной VMT.&lt;/p&gt;

&lt;p&gt;Что можно делать, если VMT одиночная? Можно усекать VMT. Ссылка на интерфейсный объект двоично подходит в любое место, где хотят IUnknown. И с каким-то потомком IUnknown это тоже сработает, вот только базовый интерфейс должен быть подлинно неизменным интерфейсом (проблема хрупкого базового класса).&lt;/p&gt;

&lt;p&gt;Ещё можно, если у какого-то интерфейса входы-выходы известны, синхронно наращивать VMT. Например, если есть воплощение IList&lt;IUnknown&amp;gt;, то можно из того же воплощения строгать&amp;nbsp;IList&lt;ISomeAnotherInterface&amp;gt; принудительным приведением типа. А вообще при должной языковой поддержке это называется lightweight generic, и есть, например, в Objective-C 2.0. В Delphi такой поддержки нет, только если хакнуть систему, силой привести свежий чистый IList&lt;IUnknown&amp;gt; к IList&lt;ISomeAnotherInterface&amp;gt;. Это работает, но Delphi это не способна проверить. IList&lt;T&amp;gt; работает на ввод и вывод и инвариантен относительно T. Тут главное, что со всеми интерфейсными ссылками нужно работать одинаково в смысле счётчика ссылок и в смысле передачи в параметры методов, везде любые интерфейсные ссылки обрабатываются одинаково в этом смысле.&lt;/p&gt;

&lt;p&gt;Ещё можно усекать VMT сквозь контейнеры (ковариантность), но Delphi тоже не способна это проверить. Инвариантный IList&lt;T&amp;gt; для этого не годится. Напрашивается IReadOnlyList&lt;T&amp;gt;, но тут уточнение. В Delphi из коробки нет IList&lt;T&amp;gt;, а в TList&lt;T&amp;gt;, если выделять&amp;nbsp;&amp;laquo;максимальное только читаемое подмножество методов&amp;raquo;, то это не то же самое, что&amp;nbsp;&amp;laquo;максимальное ковариантное подмножество методов&amp;raquo;. Максимальное ковариантное подмножество можно было бы назвать IPermutableList&lt;T&amp;gt;, так как перестановки по индексам оказываются допустимы и сортировка встроенным сравнителем оказывается допустима для элементов, которые уже оказались внутри списка через инвариантный IList&lt;T&amp;gt;. И сортировка переданным извне сравнителем допустима. А что не допустимо, так это вызывать методы Contains или IndexOf, которые двоично законтачивают встроенный сравнитель с интерфейсными ссылками, возможно, за пределами поддерживаемого диапазона.&lt;/p&gt;

&lt;p&gt;Но вот ведь незадача. Если по ссылке VMT с одиночным наследованием, и порядок нужно изобрести, то нужно определиться и выбрать только один вариант. Ну и, допустим, можно как промежуточную точку выбрать IReadOnlyList&lt;T&amp;gt;, но с условием, что из него выброшены все методы, ломающие ковариантность, то есть, IndexOf и Contains. Тогда ссылки&amp;nbsp;IReadOnlyList&lt;ISomeAnotherInterface&amp;gt; оказываются двоично совместимы во всех местах, где ожидается&amp;nbsp;IReadOnlyList&lt;IUnknown&amp;gt;. Delphi об этом не знает, так что приходится явное небезопасное приведение интерфейса использовать, но это работает. И гипотетически когда-нибудь Delphi могли бы научить таким фокусам. Ковариантности в интерфейсах.&lt;/p&gt;

&lt;p&gt;Но какому фокусу не получится научить в рамках выбранного направления, так это ковариантности за пределами одиночно наследуемая&amp;nbsp;VMT. То есть, одиночно наследуемая VMT образует рельсы, по которым можно ехать к корню (IUnknown) только в одном направлении. От&amp;nbsp;ISomeAnotherInterface к&amp;nbsp;IUnknown ведёт конечное количество остановок, и двоичная совместимость только для них. Примечание. Нет, всё же кое-что есть за пределами.&amp;nbsp;IReadOnlyList&lt;IReadOnlyList&lt;ISomeAnotherInterface&amp;gt;&amp;gt; можно свести к IUnknown двумя путями, не погрешив против двоичной совместимости, но на этом возможность множественных путей исчерпана. Множественное наследование интерфейсов в такую двоичную совместимость никак не лезет. А ведь иногда так не хватает.&lt;/p&gt;

&lt;p&gt;Как бы можно было это починить? Вспоминаем про лазейку через QueryInterface. Можно изобрести нечто такое:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;type ICompatible&lt;T&amp;gt; = interface(IUnknown) end;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;И чтобы это говорило&amp;nbsp;честное слово, что, всё, что ICompatible&lt;T&amp;gt;, если спросить QueryInterface(T), то что-то найдётся, но не обязательно тот же указатель, что и на входе. Ну и для ICompatible&lt;T&amp;gt; действовали бы какие-то расширенные правила двоичной совместимости, в которых интерфейс, собранный из множественных интерфейсов, мог бы автоматически развалиться по нескольким путям. Но это что-то не очень понятное, это лучше смотреть на Objective-C 2.0.&lt;/p&gt;

&lt;p&gt;А напоследок можно рассмотреть ещё такие особенности VMT COM, и именно в Delphi, а потом COM не в Delphi.&lt;/p&gt;

&lt;p&gt;По одиночной ссылке расположено нечто, про которое вызывающей стороне известно только что сразу по этому указателю указатель на VMT. И если через VMT вызвать метод, передать в метод указатель, то вызовется вроде бы как то, что нужно. А то, что нужно, выглядит как набор прыжковых инструкций, вычитающий известное воплощению смещение между интерфейсной VMT и началом объекта, и прыжок в метод объекта.&lt;/p&gt;

&lt;p&gt;Но это не вся история. Это так происходит, если методы не виртуальные. А если виртуальные, то из интерфейсной VMT делается прыжок по объектной VMT. А всё вместе получается два прыжка! Про COM бытует представление, что виртуальный прыжок один, но нет, их два. Потому что в общем случае невиртуальные методы неудобные. Интерфейс весь виртуальный, а в классе метод нет? Странно. Только если класс с претензией на то, чтоб быть последним. А если возможны потомки, то методы виртуальные, и у них прыжковые таблицы для интерфейсов общие, и чтобы они прыгали в разные воплощения, они прыгают тоже через VMT, но объектную VMT.&lt;/p&gt;

&lt;p&gt;Впрочем, можно поступить иначе. В Delphi интерфейсная таблица и связанный с ней набор прыжковых инструкций генерируется каждый раз, как после базового класса написать интерфейс. И выделяется новая ячейка для VMT, которая перекрывает старую VMT, но и старая VMT для того же самого интерфейса всё ещё есть. И при таком подходе можно замену сделать невиртуальными методами. Но если замена в базовом интерфейсе, то надо ещё не забыть перечислить и все унаследованные интерфейсы, Delphi это автоматически не сделает. И если их перечислить, то виртуальный вызов получается один, но какой ценой. Ценой выделения кучи дублирующих VMT, и эта куча растёт экспоненциально.&lt;/p&gt;

&lt;p&gt;В C++ как-то делается COM через полное сходство с устройством абстрактных классов C++. Какой там выбран подход, автор не изучал, но что ни выбрать, исходы такие же. Или двойной виртуальный прыжок, или экспоненциально растущая куча дополнительных VMT ради того, чтобы виртуальный прыжок мог быть один.&lt;/p&gt;

&lt;h3&gt;Динамическое разрешение метода&lt;/h3&gt;

&lt;p&gt;Встречается в Objective-C. Благодаря такому выбору, у объектов единственная &amp;laquo;идентичность&amp;raquo;. То есть, все ссылки на объект являются одним и тем же указателем. Хоть протокол (аналог интерфейса), хоть надкласс, хоть через какой вид смотреть на объект, указатель одинаковый. И поэтому проще ввести ковариантность/контравариантность. Их и ввели, в виде lightweight generics.&lt;/p&gt;

&lt;p&gt;В Objective-C одиночное наследование классов и множественные протоколы, но это ограничение Objective-C. В System Object Model множественное наследование классов. Это тот случай, когда между Анализом и Синтезом остался зазор. Когда язык программирования, будучи в чём-то простым, и не улучшил Анализ, и не улучшил Синтез. Во множественное наследование классов можно пойти, это просто разработчики Objective-C не осилили, хотя сделали многое другое.&lt;/p&gt;

&lt;p&gt;Недостатком динамического разрешения считается долгое разрешение метода, но кое-что по этому поводу можно предпринять. Дело в том, что даже в Objective-C применяются не строки как таковые, а селекторы, которые непрозрачны для программиста. В селектор можно записать подсказки для более быстрого поиска. А в System Object Model применяются жетоны методов, и сами жетоны методов можно искать через что-то вроде VMT, быстро. И жетоны методов исполняемые на некоторых платформах (OS/2 и Win32 точно да), так что если нет множественного наследования, а далеко не всегда оно есть, то рантайм может это отследить, и получается двойной виртуальный прыжок или даже одиночный. Почти как в COM, но первая VMT ищется не внутри объекта по ссылке.&lt;/p&gt;

&lt;h3&gt;Два указателя&lt;/h3&gt;

&lt;p&gt;Для полноты указан и такой вариант.&lt;/p&gt;

&lt;p&gt;Это применяется в Rust, и это делает ООП в Rust экзотическим.&amp;nbsp;Для полноты такая возможность указана, но автору не хватает опыта, чтобы вот так же с разных сторон рассмотреть, сравнить. Это похоже на COM, но у объектов единственная идентичность?&lt;/p&gt;

&lt;p&gt;Также ссылка состоит из двух указателей в C++, если применять не intrusive_ptr, а shared_ptr. Начинает вторым указателем тащиться уничтожитель.&lt;/p&gt;</content:encoded>
			<link>https://webassembly.su/blog/polimorfizm_v_jazykakh_programmirovanija/2024-12-11-10</link>
			<dc:creator>OCTAGRAM</dc:creator>
			<guid>https://webassembly.su/blog/polimorfizm_v_jazykakh_programmirovanija/2024-12-11-10</guid>
			<pubDate>Wed, 11 Dec 2024 16:52:55 GMT</pubDate>
		</item>
		<item>
			<title>Русский research про олимпиады</title>
			<description>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/44899150.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s44899150.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Минусы школьных олимпиад&lt;/strong&gt; хорошо известны: как с точки зрения освоения профессии, так и с точки зрения воспитания. Привожу мнение об олимпиадной математике &lt;a href=&quot;https://vk.com/wall-94963931_42354&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;отсюда&lt;/a&gt;&amp;nbsp;(с небольшими сокращениями):&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...</description>
			<content:encoded>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/44899150.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s44899150.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Минусы школьных олимпиад&lt;/strong&gt; хорошо известны: как с точки зрения освоения профессии, так и с точки зрения воспитания. Привожу мнение об олимпиадной математике &lt;a href=&quot;https://vk.com/wall-94963931_42354&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;отсюда&lt;/a&gt;&amp;nbsp;(с небольшими сокращениями):&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;$CUT$&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Я считаю, что олимпиадное движение развращает математиков. Они теряют способность заниматься сложными теоремами.&lt;/p&gt;

&lt;p&gt;Представьте, что кто-то решил поставить амбициозную цель: съесть быка. Вы ж понимаете, что он за один раз быка не проглотит. И даже если будет есть большими кусками, то подавится и умрёт. Чтобы съесть быка, надо отрезать маленькие кусочки, которые легко прожевать и проглотить. И ещё нужно растянуть поедание во времени, иначе просто не справишься. А ещё надо правильно хранить быка, чтоб не испортился.&lt;/p&gt;

&lt;p&gt;То есть, работа с амбициозными задачами &amp;mdash; сложная, требующая высокой культуры труда. Тут нужно максимальное облегчение каждого шага, чтобы идти длинным путём к далёкой цели. Нужна романтика пути, где впереди вершина горы, а ты движешься маленькими шажками, с передышками, чтоб дотянуть до конца.&lt;/p&gt;

&lt;p&gt;Олимпиадное движение развращает: оно совершенно ломает схему сложной работы. В олимпиадном движении нет вообще никакой далёкой цели, там вообще не нужно двигаться далеко. Просто нужно научиться глотать огромные куски за один раз. То есть, олимпиадников учат вещам, противоположным настоящей крутизне.&lt;/p&gt;

&lt;p&gt;Их вводят в заблуждение: мол, ты решил трудную олимпиадную задачу за полчаса &amp;mdash; и всё, ты супер-пупер крутой. Да нифига ты не крутой! Крутой тот, кто смог пройти длинный путь за десять лет, сделать что-то реально большое. Вот это настоящая крутизна!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://t.me/trueresearch/1859&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Комментарий Русский Research&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Трудно спорить с тем, что высокие результаты в олимпиадах говорят о выдающейся сообразительности и скорости мышления. Особенно в математике, где роль заучивания и муштры минимальна. Однако, как показывает опыт, победы в школьных олимпиадах действительно слабо коррелируют с успехами в научной работе, а зачастую не гарантируют и просто успешного окончания университета.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Математические олимпиады у нас тоже были, и по физике, но наибольший упор на олимпиады по информатике. На фото ACM 2003. И был вопиющий разрыв между интересной информатикой и олимпиадной информатикой. На интересной информатике &lt;a href=&quot;http://www.codenet.ru/progr/video/egavga/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;программирование EGA на Ассемблере&lt;/a&gt;, на олимпиадной информатике &lt;a href=&quot;https://neerc.ifmo.ru/wiki/index.php?title=%D0%9E%D0%BF%D1%80%D0%B5%D0%B4%D0%B5%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D1%81%D0%B5%D1%82%D0%B8,_%D0%BF%D0%BE%D1%82%D0%BE%D0%BA%D0%B0&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;нахождение максимального потока&lt;/a&gt;. И не встретиться им никак. Специально для нас другую интересную информатику никто не делал.&lt;/p&gt;</content:encoded>
			<link>https://webassembly.su/blog/russkij_research_pro_olimpiady/2024-07-21-9</link>
			<dc:creator>OCTAGRAM</dc:creator>
			<guid>https://webassembly.su/blog/russkij_research_pro_olimpiady/2024-07-21-9</guid>
			<pubDate>Sun, 21 Jul 2024 12:52:42 GMT</pubDate>
		</item>
		<item>
			<title>Тёмные углы Си</title>
			<description>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/89102820.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s89102820.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Для того, кому нужно сделать транслятор языка Си, нужно понимать не как на нём писать, а как лучше сделать его транслятор. Планируемый транслятор должен понимать реальные исходники, такие как libmysqlclient, libpq, а в них может встретиться всякое. Полезно изучать, на чём споткнулись другие.&lt;/p&gt;

&lt;p&gt;...</description>
			<content:encoded>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/89102820.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s89102820.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Для того, кому нужно сделать транслятор языка Си, нужно понимать не как на нём писать, а как лучше сделать его транслятор. Планируемый транслятор должен понимать реальные исходники, такие как libmysqlclient, libpq, а в них может встретиться всякое. Полезно изучать, на чём споткнулись другие.&lt;/p&gt;

&lt;p&gt;$CUT$&lt;/p&gt;

&lt;p&gt;В&amp;nbsp;этом помогает CIL, C Intermediate Language, на который предусмотрительно &lt;a href=&quot;https://webassembly.su/load/dokumentacija/docs/c_intermediate_language_uchebnik_i_rukovodstvo/6-1-0-3&quot;&gt;сохранена документация&lt;/a&gt;. Там&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/cil016.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;пишут&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h2 class=&quot;section&quot; style=&quot;text-align:start&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;&lt;span style=&quot;font-family:&quot;Times New Roman&quot;&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;font-variant-ligatures:normal&quot;&gt;&lt;span style=&quot;white-space:normal&quot;&gt;&lt;span style=&quot;text-decoration-thickness:initial&quot;&gt;&lt;span style=&quot;text-decoration-style:initial&quot;&gt;&lt;span style=&quot;text-decoration-color:initial&quot;&gt;&lt;a name=&quot;htoc50&quot;&gt;16&lt;/a&gt;&amp;nbsp;&amp;nbsp;Who Says C is Simple?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;

&lt;p style=&quot;text-align:start&quot;&gt;&lt;span style=&quot;font-size:medium&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;&lt;span style=&quot;font-family:&quot;Times New Roman&quot;&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;font-variant-ligatures:normal&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;white-space:normal&quot;&gt;&lt;span style=&quot;text-decoration-thickness:initial&quot;&gt;&lt;span style=&quot;text-decoration-style:initial&quot;&gt;&lt;span style=&quot;text-decoration-color:initial&quot;&gt;&lt;a name=&quot;sec-simplec&quot;&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:start&quot;&gt;&lt;span style=&quot;font-size:medium&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;&lt;span style=&quot;font-family:&quot;Times New Roman&quot;&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;font-variant-ligatures:normal&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;white-space:normal&quot;&gt;&lt;span style=&quot;text-decoration-thickness:initial&quot;&gt;&lt;span style=&quot;text-decoration-style:initial&quot;&gt;&lt;span style=&quot;text-decoration-color:initial&quot;&gt;When I (George) started to write CIL I thought it was going to take two weeks. Exactly a year has passed since then and I am still fixing bugs in it. This gross underestimate was due to the fact that I thought parsing and making sense of C is simple. You probably think the same. What I did not expect was how many dark corners this language has, especially if you want to parse real-world programs such as those written for GCC or if you are more ambitious and you want to parse the Linux or Windows NT sources (both of these were written without any respect for the standard and with the expectation that compilers will be changed to accommodate the program).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:start&quot;&gt;&lt;span style=&quot;font-size:medium&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;&lt;span style=&quot;font-family:&quot;Times New Roman&quot;&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;font-variant-ligatures:normal&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;white-space:normal&quot;&gt;&lt;span style=&quot;text-decoration-thickness:initial&quot;&gt;&lt;span style=&quot;text-decoration-style:initial&quot;&gt;&lt;span style=&quot;text-decoration-color:initial&quot;&gt;The following examples were actually encountered either in real programs or are taken from the ISO C99 standard or from the GCC&amp;rsquo;s testcases. My first reaction when I saw these was:&amp;nbsp;&lt;em&gt;Is this C?&lt;/em&gt;. The second one was :&amp;nbsp;&lt;em&gt;What the hell does it mean?&lt;/em&gt;.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:start&quot;&gt;&lt;span style=&quot;font-size:medium&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;&lt;span style=&quot;font-family:&quot;Times New Roman&quot;&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;font-variant-ligatures:normal&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;white-space:normal&quot;&gt;&lt;span style=&quot;text-decoration-thickness:initial&quot;&gt;&lt;span style=&quot;text-decoration-style:initial&quot;&gt;&lt;span style=&quot;text-decoration-color:initial&quot;&gt;If you are contemplating doing program analysis for C on abstract-syntax trees then your analysis ought to be able to handle these things. Or, you can use CIL and let CIL translate them into clean C code.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;h3 class=&quot;subsection&quot; style=&quot;text-align:start&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;&lt;span style=&quot;font-family:&quot;Times New Roman&quot;&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;font-variant-ligatures:normal&quot;&gt;&lt;span style=&quot;white-space:normal&quot;&gt;&lt;span style=&quot;text-decoration-thickness:initial&quot;&gt;&lt;span style=&quot;text-decoration-style:initial&quot;&gt;&lt;span style=&quot;text-decoration-color:initial&quot;&gt;&lt;a name=&quot;toc32&quot;&gt;&lt;/a&gt;&lt;a name=&quot;htoc51&quot;&gt;16.1&lt;/a&gt;&amp;nbsp;&amp;nbsp;Standard C&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;

&lt;ol class=&quot;enumerate&quot; style=&quot;color:#000000; font-family:&quot;Times New Roman&quot;; font-size:medium; font-style:normal; font-variant-ligatures:normal; font-weight:400; text-align:start; white-space:normal; text-decoration-thickness:initial; text-decoration-style:initial; text-decoration-color:initial&quot; type=&quot;1&quot;&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;Why does the following code return 0 for most values of&amp;nbsp;&lt;tt&gt;x&lt;/tt&gt;? (This should be easy.)

 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt; int x;
 return x == (1 &amp;amp;&amp;amp; x);
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex30.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;Why does the following code return 0 and not -1? (Answer: because&amp;nbsp;&lt;tt&gt;sizeof&lt;/tt&gt;&amp;nbsp;is unsigned, thus the result of the subtraction is unsigned, thus the shift is logical.)
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt; return ((1 - sizeof(int)) &amp;gt;&amp;gt; 32);
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex31.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;Scoping rules can be tricky. This function returns 5.
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt;int x = 5;
int f() {
 int x = 3;
 {
 extern int x;
 return x;
 }
}
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex32.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;Functions and function pointers are implicitly converted to each other.
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt;int (*pf)(void);
int f(void) {

 pf = &amp;amp;f; // This looks ok
 pf = ***f; // Dereference a function?
 pf(); // Invoke a function pointer? 
 (****pf)(); // Looks strange but Ok
 (***************f)(); // Also Ok 
}
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex33.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;Initializer with designators are one of the hardest parts about ISO C. Neither MSVC or GCC implement them fully. GCC comes close though. What is the final value of&amp;nbsp;&lt;tt&gt;i.nested.y&lt;/tt&gt;&amp;nbsp;and&amp;nbsp;&lt;tt&gt;i.nested.z&lt;/tt&gt;? (Answer: 2 and respectively 6).
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt;struct { 
 int x; 
 struct { 
 int y, z; 
 } nested;
} i = { .nested.y = 5, 6, .x = 1, 2 }; 
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex34.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;This is from c-torture. This function returns 1.
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt;typedef struct
{
 char *key;
 char *value;
} T1;

typedef struct
{
 long type;
 char *value;
} T3;

T1 a[] =
{
 {
 &quot;&quot;,
 ((char *)&amp;amp;((T3) {1, (char *) 1}))
 }
};
int main() {
 T3 *pt3 = (T3*)a[0].value;
 return pt3-&amp;gt;value;
}
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex35.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;Another one with constructed literals. This one is legal according to the GCC documentation but somehow GCC chokes on (it works in CIL though). This code returns 2.
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt; return ((int []){1,2,3,4})[1];
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex36.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;In the example below there is one copy of &amp;ldquo;bar&amp;rdquo; and two copies of &amp;ldquo;pbar&amp;rdquo; (static prototypes at block scope have file scope, while for all other types they have block scope).
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt; int foo() {
 static bar();
 static (*pbar)() = bar;

 }

 static bar() { 
 return 1;
 }

 static (*pbar)() = 0;
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex37.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;Two years after heavy use of CIL, by us and others, I discovered a bug in the parser. The return value of the following function depends on what precedence you give to casts and unary minus:
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt; unsigned long foo() {
 return (unsigned long) - 1 / 8;
 }
&lt;/font&gt;&lt;/pre&gt;
 See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex38.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment

 &lt;p&gt;The correct interpretation is&amp;nbsp;&lt;tt&gt;((unsigned long) - 1) / 8&lt;/tt&gt;, which is a relatively large number, as opposed to&amp;nbsp;&lt;tt&gt;(unsigned long) (- 1 / 8)&lt;/tt&gt;, which is 0.&lt;/p&gt;
 &lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class=&quot;subsection&quot; style=&quot;text-align:start&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;&lt;span style=&quot;font-family:&quot;Times New Roman&quot;&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;font-variant-ligatures:normal&quot;&gt;&lt;span style=&quot;white-space:normal&quot;&gt;&lt;span style=&quot;text-decoration-thickness:initial&quot;&gt;&lt;span style=&quot;text-decoration-style:initial&quot;&gt;&lt;span style=&quot;text-decoration-color:initial&quot;&gt;&lt;a name=&quot;toc33&quot;&gt;&lt;/a&gt;&lt;a name=&quot;htoc52&quot;&gt;16.2&lt;/a&gt;&amp;nbsp;&amp;nbsp;GCC ugliness&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;

&lt;p style=&quot;text-align:start&quot;&gt;&lt;span style=&quot;font-size:medium&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;&lt;span style=&quot;font-family:&quot;Times New Roman&quot;&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;font-variant-ligatures:normal&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;white-space:normal&quot;&gt;&lt;span style=&quot;text-decoration-thickness:initial&quot;&gt;&lt;span style=&quot;text-decoration-style:initial&quot;&gt;&lt;span style=&quot;text-decoration-color:initial&quot;&gt;&lt;a name=&quot;sec-ugly-gcc&quot;&gt;&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;ol class=&quot;enumerate&quot; style=&quot;color:#000000; font-family:&quot;Times New Roman&quot;; font-size:medium; font-style:normal; font-variant-ligatures:normal; font-weight:400; text-align:start; white-space:normal; text-decoration-thickness:initial; text-decoration-style:initial; text-decoration-color:initial&quot; type=&quot;1&quot;&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;GCC has generalized lvalues. You can take the address of a lot of strange things:
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt; int x, y, z;
 return &amp;amp;(x ? y : z) - &amp;amp; (x++, x);
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex39.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;GCC lets you omit the second component of a conditional expression.
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt; extern int f();
 return f() ? : -1; // Returns the result of f unless it is 0
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex40.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;Computed jumps can be tricky. CIL compiles them away in a fairly clean way but you are on your own if you try to jump into another function this way.
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt;static void *jtab[2]; // A jump table
static int doit(int x){
 
 static int jtab_init = 0;
 if(!jtab_init) { // Initialize the jump table
 jtab[0] = &amp;amp;&amp;amp;lbl1;
 jtab[1] = &amp;amp;&amp;amp;lbl2;
 jtab_init = 1;
 }
 goto *jtab[x]; // Jump through the table
lbl1:
 return 0;
lbl2:
 return 1;
}
 
int main(void){
 if (doit(0) != 0) exit(1);
 if (doit(1) != 1) exit(1);
 exit(0);
}
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex41.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;A cute little example that we made up. What is the returned value? (Answer: 1);
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt; return ({goto L; 0;}) &amp;amp;&amp;amp; ({L: 5;});
&lt;/font&gt;&lt;/pre&gt;
 See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex42.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;&lt;tt&gt;extern inline&lt;/tt&gt;&amp;nbsp;is a strange feature of GNU C. Can you guess what the following code computes?
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt;extern inline foo(void) { return 1; }
int firstuse(void) { return foo(); }

// A second, incompatible definition of foo
int foo(void) { return 2; }

int main() {
 return foo() + firstuse();
}
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex43.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;

 &lt;p&gt;The answer depends on whether the optimizations are turned on. If they are then the answer is 3 (the first definition is inlined at all occurrences until the second definition). If the optimizations are off, then the first definition is ignore (treated like a prototype) and the answer is 4.&lt;/p&gt;

 &lt;p&gt;CIL will misbehave on this example, if the optimizations are turned off (it always returns 3).&lt;/p&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;GCC allows you to cast an object of a type T into a union as long as the union has a field of that type:
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt;union u { 
 int i; 
 struct s { 
 int i1, i2;
 } s;
};

union u x = (union u)6;

int main() {
 struct s y = {1, 2};
 union u z = (union u)y;
}
&lt;/font&gt;&lt;/pre&gt;
 See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex44.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;GCC allows you to use the&amp;nbsp;&lt;tt&gt;__mode__&lt;/tt&gt;&amp;nbsp;attribute to specify the size of the integer instead of the standard&amp;nbsp;&lt;tt&gt;char&lt;/tt&gt;,&amp;nbsp;&lt;tt&gt;short&lt;/tt&gt;&amp;nbsp;and so on:
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt;int __attribute__ ((__mode__ ( __QI__ ))) i8;
int __attribute__ ((__mode__ ( __HI__ ))) i16;
int __attribute__ ((__mode__ ( __SI__ ))) i32;
int __attribute__ ((__mode__ ( __DI__ ))) i64;
&lt;/font&gt;&lt;/pre&gt;
 See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex45.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;The &amp;ldquo;alias&amp;rdquo; attribute on a function declaration tells the linker to treat this declaration as another name for the specified function. CIL will replace the declaration with a trampoline function pointing to the specified target.
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt; static int bar(int x, char y) {
 return x + y;
 }

 //foo is considered another name for bar.
 int foo(int x, char y) __attribute__((alias(&quot;bar&quot;)));
&lt;/font&gt;&lt;/pre&gt;
 See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex46.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class=&quot;subsection&quot; style=&quot;text-align:start&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;&lt;span style=&quot;font-family:&quot;Times New Roman&quot;&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;font-variant-ligatures:normal&quot;&gt;&lt;span style=&quot;white-space:normal&quot;&gt;&lt;span style=&quot;text-decoration-thickness:initial&quot;&gt;&lt;span style=&quot;text-decoration-style:initial&quot;&gt;&lt;span style=&quot;text-decoration-color:initial&quot;&gt;&lt;a name=&quot;toc34&quot;&gt;&lt;/a&gt;&lt;a name=&quot;htoc53&quot;&gt;16.3&lt;/a&gt;&amp;nbsp;&amp;nbsp;Microsoft VC ugliness&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;

&lt;p style=&quot;text-align:start&quot;&gt;&lt;span style=&quot;font-size:medium&quot;&gt;&lt;span style=&quot;color:#000000&quot;&gt;&lt;span style=&quot;font-family:&quot;Times New Roman&quot;&quot;&gt;&lt;span style=&quot;font-style:normal&quot;&gt;&lt;span style=&quot;font-variant-ligatures:normal&quot;&gt;&lt;span style=&quot;font-weight:400&quot;&gt;&lt;span style=&quot;white-space:normal&quot;&gt;&lt;span style=&quot;text-decoration-thickness:initial&quot;&gt;&lt;span style=&quot;text-decoration-style:initial&quot;&gt;&lt;span style=&quot;text-decoration-color:initial&quot;&gt;This compiler has few extensions, so there is not much to say here.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;ol class=&quot;enumerate&quot; style=&quot;color:#000000; font-family:&quot;Times New Roman&quot;; font-size:medium; font-style:normal; font-variant-ligatures:normal; font-weight:400; text-align:start; white-space:normal; text-decoration-thickness:initial; text-decoration-style:initial; text-decoration-color:initial&quot; type=&quot;1&quot;&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;Why does the following code return 0 and not -1? (Answer: because of a bug in Microsoft Visual C. It thinks that the shift is unsigned just because the second operator is unsigned. CIL reproduces this bug when in MSVC mode.)
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt; return -3 &amp;gt;&amp;gt; (8 * sizeof(int));
&lt;/font&gt;&lt;/pre&gt;
 &lt;/li&gt;
 &lt;li class=&quot;li-enumerate&quot; style=&quot;margin-top:6px; margin-bottom:6px&quot;&gt;Unnamed fields in a structure seem really strange at first. It seems that Microsoft Visual C introduced this extension, then GCC picked it up (but in the process implemented it wrongly: in GCC the field&amp;nbsp;&lt;tt&gt;y&lt;/tt&gt;&amp;nbsp;overlaps with&amp;nbsp;&lt;tt&gt;x&lt;/tt&gt;!).
 &lt;pre class=&quot;verbatim&quot; style=&quot;text-align:left&quot;&gt;
&lt;font color=&quot;blue&quot;&gt;struct {
 int x;
 struct {
 int y, z;
 struct {
 int u, v;
 };
 };
} a;
return a.x + a.y + a.z + a.u + a.v;
&lt;/font&gt;&lt;/pre&gt;

 &lt;p&gt;See the&amp;nbsp;&lt;a href=&quot;https://people.eecs.berkeley.edu/~necula/cil/examples/ex47.txt&quot;&gt;CIL output&lt;/a&gt;&amp;nbsp;for this code fragment&lt;/p&gt;
 &lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;</content:encoded>
			<link>https://webassembly.su/blog/tjazhjolye_storony_si/2024-07-21-8</link>
			<dc:creator>OCTAGRAM</dc:creator>
			<guid>https://webassembly.su/blog/tjazhjolye_storony_si/2024-07-21-8</guid>
			<pubDate>Sun, 21 Jul 2024 11:50:08 GMT</pubDate>
		</item>
		<item>
			<title>Летели шахматы с доски…</title>
			<description>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/81969406.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s81969406.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Восстанавливая события прошлого, приходим к тому, зачем понадобилось обращаться к WebAssembly.&lt;/p&gt;

&lt;p&gt;...</description>
			<content:encoded>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/81969406.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s81969406.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Восстанавливая события прошлого, приходим к тому, зачем понадобилось обращаться к WebAssembly.&lt;/p&gt;

&lt;p&gt;$CUT$&lt;/p&gt;

&lt;h1&gt;История через призму GUI&lt;/h1&gt;

&lt;h2&gt;Райские кущи Win32&lt;/h2&gt;

&lt;p&gt;В качестве точки отсчёта берём платформу Win32. Да, перед ней был DOS и ещё длинная цепочка платформ, но в DOS, например, не было динамически подключаемых библиотек. Вместо них, разве что, можно было написать TSR.&lt;/p&gt;

&lt;p&gt;Win32 примечательна&amp;nbsp;тем, что очень долго господствовала. От Windows 95 и где-то до Windows Seven (2009). Всё это время существовала массовая&amp;nbsp;гомогенная среда исполнения. Один программист написал, у другого человека запустилось. У кого ни возьми, у всех запустилось. В Интернет выложил, из Интернета скачали, и запустилось. Были сайты freesoft и&amp;nbsp;softportal, файлообменники.&amp;nbsp;И казалось, это будет длиться вечность.&lt;/p&gt;

&lt;p&gt;В этих райских кущах пышно расцвели самые разные языки программирования. Вообще, казалось, что Microsoft, ты давай там операционку делай, а в инструменты разработки не суйся, ты там ничего не понимаешь, только и можешь, что бейсиками своими дурацкими закармливать на все лады, то бейсик с пи-кодом, то с машинной трансляцией, то VB.NET со сборкой мусора, тьфу, нет, давайте лучше на красивом Delphi запрограммируем по заветам Вирта. О, а вот, смотрите, Ада ещё круче Delphi, а давайте с&amp;nbsp;Delphi на Аду перейдём, а вместо VCL у нас будет GNAVI. Или ObjectAda+CLAW.&lt;/p&gt;

&lt;h2&gt;Первые звоночки&lt;/h2&gt;

&lt;p&gt;Нельзя сказать, что громкие звоночки, но тут в блоге всё субъективно, и первым звоночком хочется назначить переход макос 10.4 на Интел (2004). Если до этого макос был для элиты, то к хакинтошу прикоснулось немало смертных, и в их числе оказался и автор. На территории СНГ многие в те же года прикасались к Linux, и это можно ещё связать с проникновением Интернета в дома.&lt;/p&gt;

&lt;p&gt;И тут неожиданно оказывается, что на макос и Linux нет многих полных аналогов того, что в Windows. Начинают лететь первые шахматы с доски. Жёстко привязанный к WinAPI Delphi VCL летит с доски. Delphi, портированный на Linux (Kylix), но не на макос, надолго слетел с доски, и очень нескоро вернулся.&lt;/p&gt;

&lt;h3&gt;Кроссплатформенность desktop-only&lt;/h3&gt;

&lt;p&gt;Укрепляют свои позиции так называемые кроссплатформенные графические движки. С точки зрения маковода красивее всего был XUL в основе Firefox. В современном Firefox, кажется, уже ничего не осталось от того прошлого XUL, а тогда это было перспективно. Делали кроссплатформенный плеер Songbird.&lt;/p&gt;

&lt;p&gt;Следующей по уровню комфорта была библиотека wxWidgets. На одну ступень с wxWidgets можно поставить Java-библиотеку SWT.&lt;/p&gt;

&lt;p&gt;Иерархия комфортности выстроена с точки зрения ощущения маковода. В Windows каждая программа норовила свои нестандартные меню отрисовать, чтобы выделиться, и это задавало тон. В Linux была солянка из Motif и других сейчас уже ничего не говорящих имён, и на фоне этой солянки ещё что-то торчащее незаметно. А в макос это было сильно не так. В макос была удобная продвинутая родная графическая библиотека Cocoa, и под неё багаж родных программ, унаследованный с PowerPC. И в макосе, если что-то топорщится, работает не как в системных программах, это ощущалось сильно заметно, и как правило, не в пользу программы. Вот XUL и wxWidgets автор ещё отнёс бы в положительную полуось комфортности.&lt;/p&gt;

&lt;p&gt;Отрицательную полуось открывает Qt. Программ на&amp;nbsp;Qt довелось использовать достаточно. Позже, когда Стив Джобс обосновывал, почему для iPhone такие жёсткие ограничения, он приводил в пример поганые кроссплатформенные программы на Qt, и что он не хотел превращать iPhone в гадюшник, и про Qt он макос он был прав, автор подтверждает это из первых рук. Там собственно отрисованное контекстное меню. Там не запускается жест переноса текста между программами, а вместо этого выделение сбрасывается и начинается с середины. И куча таких неудобств.&lt;/p&gt;

&lt;p&gt;Про это писал Джоэл&amp;nbsp;Спольски в статье &amp;laquo;&lt;a href=&quot;https://web.archive.org/web/20140414181948/http://russian.joelonsoftware.com/Articles/LordPalmerston.html&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Лорд Пальмерстон в программировании&lt;/a&gt;&amp;raquo;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Я размышлял о том, как выпускать приложения для Linux, Macintosh и Windows, чтобы версии для Linux и Macintosh не оказывались неоправданно дорогими. Для этого нужна некая кроссплатформенная библиотека.&lt;/p&gt;

&lt;p&gt;Такая попытка была сделана в Java, но Sun не удалось создать такие GUI, чтобы получаемые приложения выглядели достаточно натурально на каждой платформе. Примерно так же в &amp;laquo;Звёздном походе&amp;raquo; пришелец, разглядывавший землю в телескоп, точно знал, как должна выглядеть человеческая пища, но не знал, что у неё ещё должен быть какой-то вкус. У приложений Java меню находятся в правильном месте, но на клавиши они реагируют не так, как все другие приложения Windows, а диалоговые окна с закладками выглядят жутковато. И как бы вы ни старались, панели меню не будут выглядеть в точности, как панели меню Excel. Почему? Потому что Java не одобряет использование собственных средств платформы, если абстракции оказывается недостаточно. Если вы программируете в AWT, то не сможете узнать HWND окна, не сможете обращаться к Microsoft API и уж точно не сможете перехватить WM_PAINT и сделать все по-своему. И Sun достаточно хорошо разъяснила, что если вы попытаетесь это сделать, то лишитесь Чистоты. Вы Испорчены и пропадайте пропадом.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Swing и Qt работали на Windows ещё куда ни шло, но вот на макос это было постоянное расстройство.&lt;/p&gt;

&lt;p&gt;Наконец, цепочку антилидеров замыкает Gtk+. И это ещё повезло антилидировать. Потому что VCL в это новое соревнование не попал.&lt;/p&gt;

&lt;h2&gt;Мобильные платформы&lt;/h2&gt;

&lt;p&gt;Отсчёт нового неприветливого мира можно брать примерно с iPhone (2007). Он качественно отличался от топовых моделей, например, Nokia N95 на Symbian. iPhone был уже ПК в миниатюре, а&amp;nbsp;Nokia N95 ещё нет.&amp;nbsp;iPhone уже отчасти был вместо ПК, а&amp;nbsp;Nokia N95 ещё нет. Как уже было указано, Стив Джобс волевым решением ограничил Flash и всякие кроссплатформенные библиотеки, чтобы они не портили впечатление. Поэтому сложно сказать, так всё же с какого года следует вести эпоху нового&amp;nbsp;неприветливого&amp;nbsp;мира. Мира, уже ощутимо отдаляющегося от райских кущ Win32-only. По-настоящему мир стал неприветливым, когда сняли ограничение на библиотеки и языки программирования под iPhone OS, тогда она ещё так называлась. Стало можно писать не только лишь на Cocoa Touch, и не просто можно, а уже и нужно.&lt;/p&gt;

&lt;p&gt;Как если прошлых неприятностей с кроссплатформенностью было мало, теперь ещё это. Теперь ещё так называемые мобильные платформы надо поддерживать. Сплошь и рядом в соцсетях вылезали хвастуны, которые&amp;nbsp;&amp;laquo;избавились от пылесборника&amp;raquo;. Теперь у них вместо компьютера какие-то недоразумения, на которых не работают ни Windows-программы, ни Linux-программы, ни макос-программы. Ничего не поделать. Придётся подстраиваться.&lt;/p&gt;

&lt;p&gt;И снова полетели шахматы с доски. XUL решили похоронить и на desktop, и тем более не потащили в мобилы. Gtk+ не пережил пришествие мобил. С другой стороны, появились новые имена, такие как FireMonkey. Охватывает и desktop-, и мобильные платформы.&lt;/p&gt;

&lt;h2&gt;HTML5-апокалипсис&lt;/h2&gt;

&lt;p&gt;И снова у автора трудности с датировкой. В качестве опорной точки можно взять Gmail. Для желающих он был открыт с 2007го года, и тогда было это нечто из другого мира. Тогда ещё не было HTML5. Тогда был HTML4. Тогда не было WebSocket. Вместо них приходилось использовать кометные соединения или сокеты Flash. Тогда ещё была&amp;nbsp;жива Opera 9 с собственным движком Presto. И были сильны позиции Internet Explorer. И Gmail работал ещё тогда, поверх всех этих старых технологий, кроме Internet Explorer.&amp;nbsp;Для Internet Explorer был ActiveX-компонент Google Chrome Frame, а Opera какое-то время поддерживалась Gmail. Но потом поддержка Opera была прекращена.&lt;/p&gt;

&lt;p&gt;Пока Gmail был вещью в себе, это был только зародыш грядущих изменений. Всё начало меняться, когда такие приложения нового поколения начали делать все. Трудно точно установить дату, когда стали пропадать вакансии Windows и Linux разработчиков. Кажется, в 2012 такая разработка была ещё очень даже востребована, а в 2020 уже всё заполонила вебня. В качестве точки отсчёта можно выбрать рождение HTML5, которое было в 2013-2014. Поверх старых технологий делать веб-приложения как Gmail, было утомительно, нужен был HTML5, WebSocket, CORS.&lt;/p&gt;

&lt;h3&gt;Проклятье Electron&lt;/h3&gt;

&lt;p&gt;И снова полетели шахматы с доски. Люди понапокупали себе всяких умных телевизоров, для которых вроде бы и есть SDK, но мало, кто его возьмёт. Кроме того, по принципу маркетинга каждый лишний клик уменьшает конверсию, так что даже на Windows, если надо скачать и установить программу, то это совсем не то же самое, как в браузере открыть ссылку, и уже вот оно появилось. Как если было мало проблем с кроссплатформенностью desktop+mobile, теперь стала актуальна кроссплатформенность desktop+mobile+web.&lt;/p&gt;

&lt;p&gt;И web оказался таким тонким игольным ушком, через которое чуть менее, чем все, старые технологии, не пролезли. Новый стандарт кроссплатформенности практически всегда значит, что нужно сделать web-приложение, а потом это web-приложение заворачивается в браузер Electron, и вот это типа родное приложение теперь считается. А на так называемых мобильных платформах это был PhoneGap (Cordova). Ну, в общем, везде всё свелось к браузеру, обычному или завуалированному.&lt;/p&gt;

&lt;p&gt;Так смешно сейчас вспоминать сравнение wxWidgets и Gtk+ на макосе. Так смешно вспоминать неудовольствие от нашествия мобильных платформ. Когда казалось, что достигли дна, снизу постучали. Вам Qt казался марсианской едой, нос воротили, не хочу, не буду, вам mobile казался новым неприветливым миром, а нате-ка&amp;nbsp;попробуйте теперь draw.io на HTML5. Устанавливаем типа-родное приложение из Microsoft Store, а там опять двадцать пять приложение-в-браузере. Какую программу ни возьми, в ней нельзя открыть много окон. В Windows 10 старались, разделение экрана программировали, а в&amp;nbsp;приложении-в-браузере ничего невозможно разделить, потому что тупо чаты нельзя открыть в разных окнах.&lt;/p&gt;

&lt;h1&gt;Выводы&lt;/h1&gt;

&lt;p&gt;Выражать неудовольствие неконструктивно. Ничего не поделать, надо подстраиваться. Надо философски прокачать эту тему.&lt;/p&gt;

&lt;p&gt;Сейчас, если начинать какой-то проект, он с первого дня должен как-то поддерживать web. Можно говорить про прошлые технологии, что они оказались не готовы к таким драматичным изменениям, но, глядя на произошедшее, уж в новой-то технологии надо с первого дня закладывать поддержку web. Но, чтобы не хотелось плеваться от получающихся программ, можно заложить правильную кроссплатформенность.&lt;/p&gt;

&lt;p&gt;Кроссплатформенность курильщика,&amp;nbsp;&amp;mdash; это сделать всё на технологиях web, а потом для desktop и mobile упаковать web в браузеры.&lt;/p&gt;

&lt;p&gt;Кроссплатформенность здорового человека,&amp;nbsp;&amp;mdash; это сделать, чтобы в web можно было раздельно компилировать, но чтобы это не происходило в ущерб родным раздельно скомпилированными версиям программ. Через web должно быть можно подразнить и заманить в родную нормальную программу. А если не получилось заманить, то хотя бы как-то там, в web, отработать, в рамках тех ограничений, в которых существуют web-приложения.&lt;/p&gt;

&lt;p&gt;Проект транслятора WebAssembly начался как spin-off другого проекта, Objective PE. Не вдаваясь в подробности,&amp;nbsp;Objective PE про динамически загружаемые библиотеки и про переносимое GUI. Так вот, чтобы не оказаться шахматой, выброшенной с доски, потребовалось выработать какое-то решение по web, и это решение,&amp;nbsp;&amp;mdash; кроссплатформенность здорового человека. Это транслятор WebAssembly, конгруэнтный обычным платформам.&lt;/p&gt;</content:encoded>
			<link>https://webassembly.su/blog/leteli_shakhmaty_s_doski/2024-05-27-7</link>
			<dc:creator>OCTAGRAM</dc:creator>
			<guid>https://webassembly.su/blog/leteli_shakhmaty_s_doski/2024-05-27-7</guid>
			<pubDate>Sun, 26 May 2024 22:53:26 GMT</pubDate>
		</item>
		<item>
			<title>Четыре попытки асинхронизировать WebAssembly</title>
			<description>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/75869230.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s75869230.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;На многие устройства портировали NetBSD и программы для неё. На цифровом телефоне GrandStream GXV-3140 попадался портированный Pidgin. На ТВ-приставках с Venus Linux и роутерах с OpenWrt портировали много программ. WebAssembly похож на встраиваемые устройства, и всё же он остался непокорённый.&lt;/p&gt;

&lt;p&gt;...</description>
			<content:encoded>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/75869230.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s75869230.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;На многие устройства портировали NetBSD и программы для неё. На цифровом телефоне GrandStream GXV-3140 попадался портированный Pidgin. На ТВ-приставках с Venus Linux и роутерах с OpenWrt портировали много программ. WebAssembly похож на встраиваемые устройства, и всё же он остался непокорённый.&lt;/p&gt;

&lt;p&gt;$CUT$&lt;/p&gt;

&lt;h1&gt;Корни JavaScript&lt;/h1&gt;

&lt;p&gt;Исходный текст для обычных устройств отличается от того, что требуется для WebAssembly. Когда WebAssembly работает в браузере, он подвержен всё тем же ограничениям, что и программы для браузера. Необходимо постоянно возвращать управление наружу.&lt;/p&gt;

&lt;h2&gt;Проблема двухцветности&lt;/h2&gt;

&lt;p&gt;В мире JavaScript происходила эволюция: &lt;a href=&quot;https://en.wikipedia.org/wiki/Continuation-passing_style&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;CPS&lt;/a&gt;, deferred, promise, async/await. И пользоваться этим по-прежнему неудобно.&amp;nbsp;async/await порождает проблему двухцветности: нужно отслеживать, какие функции могут быть асинхронные, и либо асинхронность разрастается, перекрашивает всё в свой цвет, либо асинхронность упирается в барьер синхронного интерфейса. Тяжело обращаться с двумя цветами. Также с точки зрения разных цветов есть отличия даже в стандартных классах. Например, у массива Array есть метод&amp;nbsp;forEach, но он сам синхронный, и он ожидает на вход синхронную функцию. Стандартного асинхронного аналога нет. Под аналогом следует понимать метод массива, который вызовет обработку каждого элемента, дожидаясь обработки прошлого.&lt;/p&gt;

&lt;h2&gt;Странный параллельный запуск&lt;/h2&gt;

&lt;p&gt;Можно пойти другим путём. Можно запустить обработку элементов параллельно, а потом дожидаться результатов. Такого готового асинхронного метода тоже нет, а наивная попытка написать вскрывает ещё странные особенности асинхронных функций. Вызовы асинхронных функций интуитивно воспринимаются как запуск в другом потоке, но на самом деле они могут выполнить множество операций перед тем, как заснуть и вернуть обещание.&lt;/p&gt;

&lt;h1&gt;Специфика WebAssembly&lt;/h1&gt;

&lt;p&gt;В-принципе, можно пытаться повторять тот же путь, что и в JavaScript, и дойти до async/await и всех проблем с ними. Но посмотрим, что пробовали ещё.&lt;/p&gt;

&lt;h2&gt;Интерпретатор&lt;/h2&gt;

&lt;p&gt;Очень популярное решение в подобных ситуациях: заменять асинхронный участок кода интерпретируемым. В EmScripten это называлось Emterpreter. Недостаток: замедление в 10 раз и большие проблемы с двухцветностью. Сейчас эта возможность устаревшая.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;WARNING: The Emterpreter was removed in emscripten 1.39.17. For details, see&amp;nbsp;&lt;a href=&quot;https://github.com/emscripten-core/emscripten/blob/main/ChangeLog.md#13917-06052020&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;the changelog&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Asyncify&lt;/h2&gt;

&lt;p&gt;Другой попыткой в EmScripten был режим asyncify. Во всех возможных точках останова делались дубликаты функций, в которые можно и продолжить с этой точки. Это, по идее, должно быть максимально быстро, но это приводило к чрезмерному разрастанию кода, который можно продолжить со всех возможных точек останова. Эту возможность объявили устаревшей ещё раньше, чем Emterpreter.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;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).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Типизированные продолжения&lt;/h2&gt;

&lt;p&gt;В 2020м было добавлено &lt;a href=&quot;https://github.com/WebAssembly/design/issues/1359&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;предложение добавить в WebAssembly типизированные продолжения&lt;/a&gt;. Пока не принято, то есть, в браузерах не доступно и, может быть, не будет доступно.&lt;/p&gt;

&lt;h2&gt;JavaScript Promise Integration (JSPI)&lt;/h2&gt;

&lt;p&gt;Другой попыткой было сохранение стека WebAssembly за кулисами при попытке взаимодействовать с асинхронным кодом JavaScript. Это было реализовано в одном из браузеров, но требует включения экспериментальных возможностей. Возможно, это так и не будет принято. Также при использовании этой возможности наложены довольно жёсткие ограничения на размер стека, который может быть сохранён на будущее.&lt;/p&gt;

&lt;h1&gt;Ещё одна попытка&lt;/h1&gt;

&lt;p&gt;Последнее слово ещё не сказано. Автор видит перспективным идти не по пути CPS и его вариаций вплоть до async/await, а по пути&amp;nbsp;&lt;a href=&quot;https://dl.acm.org/doi/10.1145/317636.317779&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;батутизации (trampolined style)&lt;/a&gt;. Разница: в CPS вызов преобразуется в вызов, и возврат тоже преобразуется в вызов. При батутизации вызов превращается в возврат, и возврат тоже воплощён через возврат. Для исполнения батутизированного кода нужен рантайм, нужен батут, но вот эта комбинация из батута и батут-преобразованного кода и является, по мнению автора, лучшим решением. Автор ставит цель написать транслятор языка Си в WebAssembly с батут-преобразованием. В отличие от Asyncify, оно 1:1, и размер кода не раздувается. Батут похож на интерпретатор, но не замедлен&amp;nbsp;в 10 раз. Ожидаемое замедление в 3 раза, но в обмен на это свобода писать в удобном синхронном стиле и не решать проблемы двухцветности. Такой транслятор должен быть наиболее похож на трансляторы для обычных платформ. Из одних исходников должно быть возможно компилировать для обычных платформ обычными трансляторами, и этим новым транслятором для WebAssembly, по возможности, без необходимости подстраиваться под особенности браузера.&lt;/p&gt;</content:encoded>
			<link>https://webassembly.su/blog/chetyre_popytki_asinkhronizirovat_webassembly/2024-04-25-6</link>
			<dc:creator>OCTAGRAM</dc:creator>
			<guid>https://webassembly.su/blog/chetyre_popytki_asinkhronizirovat_webassembly/2024-04-25-6</guid>
			<pubDate>Wed, 24 Apr 2024 21:48:52 GMT</pubDate>
		</item>
		<item>
			<title>Книга Дракона не очень?</title>
			<description>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/14746767.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s14746767.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Редактор Софтпанорамы Н.Н. Безруков &lt;a href=&quot;https://softpanorama.org/Bookshelf/Computers/compilers.shtml&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;про книгу Дракона&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compiler construction (see also&amp;nbsp;&lt;a href=&quot;https://softpanorama.org/Algorithms/compilers.shtml&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;my page with the collection of links&lt;/a&gt;) stopped to be a black art approximately after publishing of&amp;nbsp; famous&amp;nbsp;&lt;a href=&quot;https://softpanorama.org/Bookshelf/Computers/compilers.shtml#Gries71&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;David Gries&lt;/a&gt;&apos; book. Now it&apos;s a pretty established field but the truth is that there are few good books on the topic. Widely praised&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://www.amazon.com/exec/obidos/ASIN/0201100886/ref=nikolaibezroukov&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Compilers Principles, Techniques, and Tools&lt;/a&gt;&amp;nbsp;by Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman is in my opinion a weak book that stresses too much syntax parsing and more obscures&amp;nbsp; then enlighten the design of compiler.&amp;nbsp;&lt;b&gt;&lt;i&gt;In other words the Dragon Book is way overhyped.&amp;nbsp;&lt;/i&gt;&lt;/b&gt;It&lt;b&gt;&lt;i&gt;&amp;nbsp;&lt;/i&gt;&lt;/b&gt;is confusing and a complete nightmare to understand, especially for students. It actually kills interest to compiler writing instead of enhancing it. the authors have penchant to use useless formalisms (&quot;art for the sake of the art&quot;).&amp;nbsp; It have some value for instructors but almost none for students.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;А что он рекомендует для разработки трансляторов?&lt;/p&gt;

&lt;p&gt;...</description>
			<content:encoded>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/14746767.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s14746767.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Редактор Софтпанорамы Н.Н. Безруков &lt;a href=&quot;https://softpanorama.org/Bookshelf/Computers/compilers.shtml&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;про книгу Дракона&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compiler construction (see also&amp;nbsp;&lt;a href=&quot;https://softpanorama.org/Algorithms/compilers.shtml&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;my page with the collection of links&lt;/a&gt;) stopped to be a black art approximately after publishing of&amp;nbsp; famous&amp;nbsp;&lt;a href=&quot;https://softpanorama.org/Bookshelf/Computers/compilers.shtml#Gries71&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;David Gries&lt;/a&gt;&apos; book. Now it&apos;s a pretty established field but the truth is that there are few good books on the topic. Widely praised&amp;nbsp;&amp;nbsp;&lt;a href=&quot;https://www.amazon.com/exec/obidos/ASIN/0201100886/ref=nikolaibezroukov&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Compilers Principles, Techniques, and Tools&lt;/a&gt;&amp;nbsp;by Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman is in my opinion a weak book that stresses too much syntax parsing and more obscures&amp;nbsp; then enlighten the design of compiler.&amp;nbsp;&lt;b&gt;&lt;i&gt;In other words the Dragon Book is way overhyped.&amp;nbsp;&lt;/i&gt;&lt;/b&gt;It&lt;b&gt;&lt;i&gt;&amp;nbsp;&lt;/i&gt;&lt;/b&gt;is confusing and a complete nightmare to understand, especially for students. It actually kills interest to compiler writing instead of enhancing it. the authors have penchant to use useless formalisms (&quot;art for the sake of the art&quot;).&amp;nbsp; It have some value for instructors but almost none for students.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;А что он рекомендует для разработки трансляторов?&lt;/p&gt;

&lt;p&gt;$CUT$&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;One of the most underestimated books on compliers is probably the first volume of&amp;nbsp;&lt;a href=&quot;https://softpanorama.org/Bookshelf/Computers/Classics/taocp.shtml&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;The Art Of Computer Programming&lt;/a&gt;, the book that should be on the shelf of any complier writer. Algorithms described in this book, especially coroutines and those related to the trees, as well as MIX assembler are useful examples that any compiler writer can use.&amp;nbsp; Generally a book with a complete code of a simple compiler is a good start as theoretical methods exposed in books like&amp;nbsp;&lt;a href=&quot;https://www.amazon.com/exec/obidos/ASIN/0201100886/ref=nikolaibezroukov&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Compilers Principles, Techniques, and Tools&lt;/a&gt;&amp;nbsp;by Alfred V. Aho, Ravi Sethi, Jeffrey D. Ullman at the beginning looks incomprehensible and at end are not that practical.&amp;nbsp;&amp;nbsp;Paradoxically only after a while own compiler or interpreter one starts to understand how primitive thinking all those &quot;theorists&quot; have about this complex subject and how far detached they are from reality in their writings. In this sense, for a practitioner of the field,&amp;nbsp; sound skepticism toward those &quot;pseudo theories&quot; make perfect sense :-).&lt;/p&gt;

&lt;p&gt;At the same time compliers are very interesting, fascinating area, and on abstract level the methods used for their writing are essentially higher level programming paradigm which can be called&amp;nbsp;&amp;nbsp;&lt;b&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Language-oriented_programming&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;language-oriented programming&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded>
			<link>https://webassembly.su/blog/kniga_drakona_ne_ochen/2024-04-08-5</link>
			<dc:creator>OCTAGRAM</dc:creator>
			<guid>https://webassembly.su/blog/kniga_drakona_ne_ochen/2024-04-08-5</guid>
			<pubDate>Mon, 08 Apr 2024 07:22:55 GMT</pubDate>
		</item>
		<item>
			<title>Wasm, — это новый DOS</title>
			<description>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/95641782.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s95641782.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Массовое распространение клонов IBM PC привело к резкому увеличению количества людей, активно занимающихся программированием на компьютере, а следовательно, и прослойки компьютерных &quot;фанатов&quot;. Если раньше этот тип людей встречался в основном в университетских городках и больших вычислительных центрах, то с распространением клонов IBM PC ситуация существенно изменилась. Обладателями мощных и в то же время дешёвых компьютеров стали школьники, пенсионеры, а также другие лица, располагавшие, помимо желания попробовать свои силы в программировании, еще и значительным количеством свободного времени.&lt;/p&gt;

&lt;p&gt;Как и в других областях человеческой деятельности, спектр отношения людей к программированию и вычислительным машинам очень широк: от ненависти, через полное безразличие до патологической привязанности или зависимости, которую можно квалифицировать как манию. Всякий работавший в вычислительном центре на больших ЭВМ и видевший, как к концу второй смены некоторые программисты наспех вносят плохо продуманные изменения в свои программы и умоляют электронщиков дать еще минутку, чтобы посмотреть, что получится, узнает сцену, описанную Ф.М.Достоевским в романе &quot;Игрок&quot;:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...</description>
			<content:encoded>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/95641782.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s95641782.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Массовое распространение клонов IBM PC привело к резкому увеличению количества людей, активно занимающихся программированием на компьютере, а следовательно, и прослойки компьютерных &quot;фанатов&quot;. Если раньше этот тип людей встречался в основном в университетских городках и больших вычислительных центрах, то с распространением клонов IBM PC ситуация существенно изменилась. Обладателями мощных и в то же время дешёвых компьютеров стали школьники, пенсионеры, а также другие лица, располагавшие, помимо желания попробовать свои силы в программировании, еще и значительным количеством свободного времени.&lt;/p&gt;

&lt;p&gt;Как и в других областях человеческой деятельности, спектр отношения людей к программированию и вычислительным машинам очень широк: от ненависти, через полное безразличие до патологической привязанности или зависимости, которую можно квалифицировать как манию. Всякий работавший в вычислительном центре на больших ЭВМ и видевший, как к концу второй смены некоторые программисты наспех вносят плохо продуманные изменения в свои программы и умоляют электронщиков дать еще минутку, чтобы посмотреть, что получится, узнает сцену, описанную Ф.М.Достоевским в романе &quot;Игрок&quot;:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;$CUT$&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&quot;В одиннадцатом часу у игорных столов остаются настоящие, отчаянные игроки, для которых на водах существует только одна рулетка, которые и приехали для нее одной, которые плохо замечают, что вокруг них происходит, и ничем не интересуются весь сезон, а только играют с утра до ночи и готовы были бы играть, пожалуй, и всю ночь до рассвета, если б можно было. И всегда они с досадой расходятся, когда в двенадцать часов закрывают рулетку. И когда старший крупер перед закрытием рулетки около двенадцати часов, возглашает: &quot;Les trois derniers coups, messieurs!&quot; (Три последних игры (букв.: удара), господа - прим. перев.), то они готовы иногда проставить на этих трех последних ударах все, что у них есть в кармане, - и действительно тут-то наиболее и проигрываются&quot; [Полн. собр. соч. в 30-ти томах. - Л.: Наука, т.5, 1973, c.292].&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Снимок экрана из игры &lt;a href=&quot;https://store.steampowered.com/app/370360/TIS100/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;TIS-100&lt;/a&gt; от &lt;a href=&quot;https://store.steampowered.com/bundle/2925/The_Zachtronics_Puzzle_Pack/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;Zachtronics&lt;/a&gt;.&amp;nbsp;Цитата из главы&amp;nbsp;1.2.1. &amp;laquo;Хакеры&amp;raquo; из книги Н.Н. Безрукова&amp;nbsp;&amp;laquo;Компьютерная вирусология&amp;raquo;. Книга вышла в 1991м году и ещё передаёт дух невероятной экзальтации той эпохи. Также Н.Н. Безруков, редактор Софтпанорамы, &lt;a href=&quot;https://softpanorama.org/OFM/Paradigm/Ch03/norton_commander.shtml&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;рекомендует&lt;/a&gt; книгу &lt;a href=&quot;https://webassembly.su/load/knigi/istorija_it/hard_drive_bill_gates_and_the_making_of_the_microsoft_empire_james_wallace_1992/3-1-0-1&quot;&gt;Hard drive: Bill Gates and the making of the Microsoft empire&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;youtube-embed-wrapper&quot; style=&quot;position:relative;padding-bottom:56.25%;padding-top:30px;height:0;overflow:hidden&quot;&gt;&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/76wzB8-GB98&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;h1&gt;Второй раз в реку&lt;/h1&gt;

&lt;p&gt;Увы, эпоха ушла. Запрещают везде доступы. Блокируют чужой код цифровой&amp;nbsp;подписью. Наверное, правильно делают. Но куда теперь податься хакерам.&amp;nbsp;Как войти в эту реку второй раз?&lt;/p&gt;

&lt;div class=&quot;youtube-embed-wrapper&quot; style=&quot;position:relative;padding-bottom:56.25%;padding-top:30px;height:0;overflow:hidden&quot;&gt;&lt;iframe allowfullscreen=&quot;&quot; frameborder=&quot;0&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/VLfvnimHXVc?rel=0&quot; style=&quot;position:absolute;top:0;left:0;width:100%;height:100%&quot; width=&quot;640&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;p&gt;Для этого надо проанализировать, а что делало эту реку такой?&lt;/p&gt;

&lt;h2&gt;Прозрачность&lt;/h2&gt;

&lt;p&gt;DOS был примечателен тем, что не утаивал от программиста подробности реализации. Всё в системе было как на ладони. Особенно, когда появились отладчики вроде AVPUTIL. Всю память реального режима можно посмотреть. В отладчике можно по инструкциям походить, посмотреть, как это всё работает. И, посмотрев, сделать и своё.&lt;/p&gt;

&lt;h2&gt;Пространство для мастерства&lt;/h2&gt;

&lt;p&gt;Разрабатывать под DOS было непросто, но у кого получалось, те получали признание.&lt;/p&gt;

&lt;p&gt;Например, FoxPro был движком баз данных в формате dbf, и средой разработки со своим языком программирования. Управление базами&amp;nbsp;данных в DOS требовало мастерского обращения со всевозможными типами расширенной памяти (UMB, HMA, EMS, XMS) и выгрузкой на диск. Расширенная память так устроена, что в каждый момент времени программы видят не всю выделенную память, а только лишь окна. Окна можно переключать, чтоб отображали разные участки памяти. Для работы с этими сущностями в FoxPro применяются аналоги указателей, и всё это за несколько лет до того, как обобщения указателей начали появляться в C++ (перегрузка operator *).&lt;/p&gt;

&lt;p&gt;Отдельный разговор можно посвятить тому, как управляться с видеокартой. Это касается и графических режимов, и текстовых. В текстовых режимах компьютер работал заметно побыстрее, но ведь так хотелось немного красоты. Так что программисты перепрограммировали шрифт и придавали особый вид своим программам. Это MS-DOS Shell, Norton Utilities, ASPLoader, Acronis OS Selector.&lt;/p&gt;

&lt;p&gt;С появлением защищённого режима жизнь программистов стала проще не во всём. В DPMI (DOS Protected Mode Interface) основным режимом по-прежнему является реальный. То есть, чтобы записать на диск или прочитать с диска, или провзаимодействовать с мышью, нужно постоянно выходить из защищённого режима обратно в реальный. Для этих взаимодействий в&amp;nbsp;DPMI предусмотрено&amp;nbsp;API создания двусторонних переходов. Можно выделять новые заглушки. Это ресурс, а ресурсами надо управлять. Где есть выделение, там нужно и освобождение.&lt;/p&gt;

&lt;h2&gt;Широкая аудитория&lt;/h2&gt;

&lt;p&gt;И последняя вишенка на торте. То, что сделал программист, было, кому посмотреть. Ведь так-то и сейчас хватает любителей &lt;a href=&quot;http://dgmag.in/&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;даунгрейда&lt;/a&gt;. Но понятно, что нас мало, и мы кто в лес, кто по дрова. Кому-то дорога эпоха DOS, у кого-то навсегда Windows 98, а у кого-то Windows XP, QIP и ICQ. В настоящую эпоху DOS ведь всё было не так. У всех было примерно одно и то же, и даже между DOS и Windows 9x разница была ещё не столь велика. В Windows 9x можно было создать такой ярлык (pif) программы, который перезагрузит компьютер в эту программу в чистом DOS. Только с Windows Millenium, 2000 и XP начал ломаться привычный мир.&lt;/p&gt;

&lt;p&gt;То, что сделал программист, было практически единственным способом это сделать. Ну, то есть, если сейчас писать под DOSBox, то можно ведь и без DOSBox сделать то же самое, но лучше. А тогда DOS был практически всем. Практически абсолютом.&lt;/p&gt;

&lt;h1&gt;Новая река&lt;/h1&gt;

&lt;h2&gt;Широкая аудитория&lt;/h2&gt;

&lt;p&gt;По указанным трём критериям на роль нового захода в реку&amp;nbsp;внезапно хорошо начинает подходить WebAssembly. Среди любителей даунгрейда есть мнение, что новый DOS&amp;nbsp;&amp;mdash; это UEFI. То, что в современных компьютерах вместо BIOS. Ведь там можно запускать exe, там есть&amp;nbsp;UEFI Shell. Под UEFI написали тетрис и файловый менеджер. Да, это впечатляет, но это слишком прямая аналогия. Среди проанализированных пунктов выше хромает по части&amp;nbsp;&amp;laquo;Широкая аудитория&amp;raquo;. Многие ли станут перезагружать свой компьютер в чистую среду UEFI? Да даже в виртуальную машину загрузить не хочется. Не правда ли.&lt;/p&gt;

&lt;p&gt;В этом выгодное отличие WebAssembly. Он теперь есть в каждом браузере. Сможешь его покорить? Иди и возьми его. В маркетинге есть правило, что каждое&amp;nbsp;лишнее&amp;nbsp;действие уменьшает конверсию, а в WebAssembly с этим всё максимально хорошо. Поставь на любую страницу, если есть, что поставить.&lt;/p&gt;

&lt;h2&gt;Прозрачность&lt;/h2&gt;

&lt;p&gt;WebAssembly не позволяет вглядеться, что происходит в недрах браузера, но то, что происходит в самом&amp;nbsp;WebAssembly, так же прозрачно, как это было в DOS. Ну, примерно. Полной аналогии, конечно, нет, но нам хватит. Больше всего не хватает, что чужие программы не в WebAssembly, они-то чаще всего в JavaScript. С другой стороны, довольно часто встроенным отладчиком браузера можно изучать и чужой JavaScript тоже.&lt;/p&gt;

&lt;p&gt;В отличие от DOS, в WebAssembly придётся самим себя развлекать, самим наполнять и память Wasm.Memory, и другие ресурсы Wasm.&lt;/p&gt;

&lt;h2&gt;Пространство для мастерства&lt;/h2&gt;

&lt;p&gt;А вот с этим полный порядок. В DOS DPMI было управление замыканиями для перехода между реальным режимом и защищённым. В WebAssembly системному программисту&amp;nbsp;полно развлечений для связи&amp;nbsp;WebAssembly и JavaScript, а без JavaScript не получится взаимодействовать с браузером.&amp;nbsp;JavaScript играет роль как бы реального режима в DPMI. То, куда надо выходить, чтобы взаимодействовать с окружающей действительностью.&lt;/p&gt;

&lt;p&gt;Но особенное мастерство требуется в организации передачи управления.&amp;nbsp;WebAssembly встроен в браузер и наследует его ограничения. Принципиальное ограничение,&amp;nbsp;&amp;mdash; нельзя долго исполнять код. В достаточно обозримое время нужно возвращать управление на самый верх. Управление внутрь&amp;nbsp;WebAssembly попадает только из JavaScript, так что надо полностью выходить наверх из WebAssembly, и дальше выходить из JavaScript тоже, передавая управление в сам браузер.&lt;/p&gt;

&lt;p&gt;Можно, например, отправить данные по WebSockets, но чтобы получить ответ, надо повесить обработчик событий и полностью выйти. И так много, где. Это вызов!&lt;/p&gt;

&lt;p&gt;Это пространство для мастерства даже больше, чем в DOS. Это такое пространство для мастерства, как при разработке новой операционной системы во времена, когда люди активно экспериментировали с ними. Ещё в 2000е было нормально практиковать мультизагрузку операционных систем. Попробовать у себя Linux или другую операционную систему.&lt;/p&gt;

&lt;p&gt;В новой операционной системе для WebAssembly вместо прерываний события браузера. Это и таймер (window.setTimer, window.setTimeout), и весь UI.&lt;/p&gt;</content:encoded>
			<link>https://webassembly.su/blog/wasm_ehto_novyj_dos/2024-04-08-4</link>
			<dc:creator>OCTAGRAM</dc:creator>
			<guid>https://webassembly.su/blog/wasm_ehto_novyj_dos/2024-04-08-4</guid>
			<pubDate>Sun, 07 Apr 2024 23:54:15 GMT</pubDate>
		</item>
		<item>
			<title>Советская Java</title>
			<description>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/47153759.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s47153759.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Любопытные вещи можно вычитать в &lt;a href=&quot;https://www.iis.nsk.su/memories/wgroup_5&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;материалах Рабочей группы по реализации языков программирования (РГ РЯП)&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Одним из основных вопросов докладов и дискуссий был вопрос уровня языка. Отмечалось, что разработка больших и сложноорганизованных программ на языках низкого уровня увеличивает возможность появления ошибок в программах и затрудняет их обнаружение и исправление. Это приводит к затяжке сроков разработки, снижению надёжности программного продукта и затрудняет его сопровождение.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;hellip;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Семинар отметил, с одной стороны, необходимость широкого внедрения существующих АРМ разработчика программного обеспечения типа АРМ2-05 с языками ассемблерного типа, кросс-систем, настраиваемых на устройства МПТ, и, с другой стороны, перспективность и необходимость расширения области применения &lt;strong&gt;языков типа ЯВА&lt;/strong&gt; с заменой ими фирменных ассемблеров.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;...</description>
			<content:encoded>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/47153759.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s47153759.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Любопытные вещи можно вычитать в &lt;a href=&quot;https://www.iis.nsk.su/memories/wgroup_5&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;материалах Рабочей группы по реализации языков программирования (РГ РЯП)&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Одним из основных вопросов докладов и дискуссий был вопрос уровня языка. Отмечалось, что разработка больших и сложноорганизованных программ на языках низкого уровня увеличивает возможность появления ошибок в программах и затрудняет их обнаружение и исправление. Это приводит к затяжке сроков разработки, снижению надёжности программного продукта и затрудняет его сопровождение.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;hellip;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Семинар отметил, с одной стороны, необходимость широкого внедрения существующих АРМ разработчика программного обеспечения типа АРМ2-05 с языками ассемблерного типа, кросс-систем, настраиваемых на устройства МПТ, и, с другой стороны, перспективность и необходимость расширения области применения &lt;strong&gt;языков типа ЯВА&lt;/strong&gt; с заменой ими фирменных ассемблеров.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;$CUT$&lt;/p&gt;

&lt;p&gt;Звучит свежо? Свежо как свежесть 1996го года в США. Вот только действие происходит в 1983м году в СССР. Удивительно, но факт. У нас заранее случайно выбрали такое же название. В Советском Союзе это не остров, на котором&amp;nbsp;выращивают кофе. В Советском Союзе это аббревиатура:&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;&lt;strong&gt;Я&lt;/strong&gt;зык &lt;strong&gt;В&lt;/strong&gt;место &lt;strong&gt;А&lt;/strong&gt;ссемблера&lt;/p&gt;

&lt;p&gt;Кое-что про советскую Java можно найти почитать в &lt;a href=&quot;https://ershov.iis.nsk.su/ru/node/776205&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;архиве академика А.П. Ершова&lt;/a&gt;.&lt;/p&gt;</content:encoded>
			<link>https://webassembly.su/blog/sovetskaja_java/2024-04-08-3</link>
			<dc:creator>OCTAGRAM</dc:creator>
			<guid>https://webassembly.su/blog/sovetskaja_java/2024-04-08-3</guid>
			<pubDate>Sun, 07 Apr 2024 21:11:25 GMT</pubDate>
		</item>
		<item>
			<title>Сравнение WebAssembly и Portable Executable (dll)</title>
			<description>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/54037123.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s54037123.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Программисты хорошо знакомы с Portable Executable, форматом исполняемых файлов для Windows. WebAssembly сулит все те же возможности, что и PE, в браузере. Но у них разный путь становления, что привело к фундаментальным различиям. Различия можно отчасти сгладить, и всё же придётся иметь их ввиду.&lt;/p&gt;

&lt;p&gt;...</description>
			<content:encoded>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/54037123.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s54037123.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Программисты хорошо знакомы с Portable Executable, форматом исполняемых файлов для Windows. WebAssembly сулит все те же возможности, что и PE, в браузере. Но у них разный путь становления, что привело к фундаментальным различиям. Различия можно отчасти сгладить, и всё же придётся иметь их ввиду.&lt;/p&gt;

&lt;p&gt;$CUT$&lt;/p&gt;

&lt;h1&gt;Память&lt;/h1&gt;

&lt;p&gt;Модули Portable Executable имеют доступ к единому адресному пространству процесса. Модули WebAssembly должны импортировать или экспортировать блок памяти. Впрочем, могут не пользоваться массивной памятью или же пользоваться встроенной памятью, но не экспортировать наружу. Модуль Wasm, экспортирующий блок памяти, похож на PE exe: exe является точкой роста, он определяет содержимое своей памяти, а все остальные модули (PE dll) входят в виртуальное адресное адресное пространство, определённое PE exe. В частности, это проявляется в том, что до недавних усилий по повышению безопасности многие PE exe нельзя было перебазировать из-за отсутствия релокаций.&lt;/p&gt;

&lt;p&gt;Наиболее гибкие модули WebAssembly, импортирующие блок памяти Wasm.Memory, и они похожи на PE dll. Из-за ограничений WebAssembly имеет смысл и аналоги exe делать в виде модулей Wasm с импортом памяти. Потому что хотя exe и первый определяет виртуальную память, но запуск exe требует подключения всех dll, и только после подключения dll запускается исполнение exe, и воспроизведение такого поведения в Wasm всё же требует, чтобы Wasm.Memory импортировался.&lt;/p&gt;

&lt;h1&gt;Прямая связь модулей&lt;/h1&gt;

&lt;p&gt;Однако если можно почти любую&amp;nbsp;PE dll брать и подключать в программу, объявив, конечно, внешние функции, то из-за особенностей WebAssembly нельзя того же утверждать про произвольные модули WebAssembly. В HTML5 практически сложно назвать что-то главной программой, так что там не должно быть аналогов PE exe, и всё же модули Wasm часто устроены таким способом, который не подходит для загрузки их как dll в общую память, в том числе из-за неправильного подключения Wasm.Memory. Про WebAssembly можно утверждать, что модули&amp;nbsp;WebAssembly заворачиваются в интерфейс для работы с ними из JavaScript, но не гарантируется&amp;nbsp;прямая связь&amp;nbsp;WebAssembly-WebAssembly аналогично прямой связи dll-dll или exe-dll в Portable Executable. Без специальных усилий со стороны инструментов разработки вместо&amp;nbsp;WebAssembly-WebAssembly можно получить:&amp;nbsp;WebAssembly-JavaScript-WebAssembly.&lt;/p&gt;

&lt;h1&gt;Подключение модулей&lt;/h1&gt;

&lt;p&gt;Portable Executable содержит указания, по каким именам загружать dll. Такие файлы или ресурсы, как config и manifest, могут ещё немного скорректировать места поиска dll. Таким образом, запуск exe или LoadLibrary для dll позволяют загрузить программу или библиотеку со всеми их зависимостями автоматически. В среде браузера это более сложный процесс, и сложность перекладывается на плечи программиста. В частности, в обычном окружении браузера нельзя или крайне нежелательно делать синхронную загрузку файла&amp;nbsp;(в WebWorker можно). Из-за этого сложность загрузки перекладывается на плечи программиста таким образом, что инстанциация модуля WebAssembly требует предоставления его подключенных библиотек в уже инстанциированном виде. А для этого нужно было библиотеки уже как-то рекурсивно найти и асинхронно загрузить. Этот дополнительный код пишется разработчиками трансляторов, и пишется по-разному.&lt;/p&gt;

&lt;h1&gt;Положительные стороны WebAssembly&lt;/h1&gt;

&lt;p&gt;В Portable Executable большую популярность получили структуры данных со ссылками на виртуальные адреса. Как само собой разумеющееся предполагается, что PE exe или dll загружен с диска в память, и тогда обходить эти структуры данных становится посильной задачей. Но менять многое невозможно надёжно, либо избыточно сложно. Например, было непросто написать такую программу, как ResHacker. У WebAssembly формат файлов лучше типизирован, с ним удобнее работать в исходном (файловом) виде.&lt;/p&gt;

&lt;h1&gt;Итог&lt;/h1&gt;

&lt;p&gt;Компилировать WebAssembly можно так, чтобы они были похожи на Portable Executable dll, но от сторонних разработчиков не приходится ожидать, чтобы они так компилировали.&lt;/p&gt;

&lt;p&gt;WebAssembly устроен как конструктор сделай-сам. А сделать самому можно по-разному. Не каждый программист занимается таким конструированием, но разработчики разных трансляторов делают свои воплощения, отличающиеся в подходах. Компилировать WebAssembly как Portable Executable dll теоретически можно, но чужие скомпилированные wasm не работают как dll. И если какой-то новый транслятор заявляет поддержку WebAssembly, то вовсе не обязательно продукты его трансляции получится загружать и вызывать удобно как dll.&lt;/p&gt;

&lt;p&gt;Отчасти различия в инструментариях призваны сгладить спецификации&amp;nbsp;&lt;a href=&quot;https://github.com/WebAssembly/tool-conventions&quot; rel=&quot;noopener&quot; target=&quot;_blank&quot;&gt;WebAssembly Tool Conventions&lt;/a&gt;&lt;/p&gt;</content:encoded>
			<link>https://webassembly.su/blog/sravnenie_webassembly_i_portable_executable_dll/2024-03-21-2</link>
			<dc:creator>OCTAGRAM</dc:creator>
			<guid>https://webassembly.su/blog/sravnenie_webassembly_i_portable_executable_dll/2024-03-21-2</guid>
			<pubDate>Thu, 21 Mar 2024 19:53:41 GMT</pubDate>
		</item>
		<item>
			<title>WebAssembly тяжелее ассемблера</title>
			<description>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/59751596.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s59751596.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Ура, свершилось? Прямой доступ к машинным кодам прямо из браузера?&lt;/p&gt;

&lt;p&gt;Нет, не совсем так. Простые компилируемые в машинные коды программы на таких языках, как Ada и Delphi, всё ещё остаются шустрее. И вот, почему.&lt;/p&gt;

&lt;p&gt;...</description>
			<content:encoded>&lt;p&gt;&lt;!--IMG1--&gt;&lt;a href=&quot;https://webassembly.su/_bl/0/59751596.jpg&quot; class=&quot;ulightbox&quot; target=&quot;_blank&quot; title=&quot;Нажмите для просмотра в полном размере...&quot;&gt;&lt;img style=&quot;margin:0;padding:0;border:0;&quot; src=&quot;https://webassembly.su/_bl/0/s59751596.jpg&quot; align=&quot;&quot; /&gt;&lt;/a&gt;&lt;!--IMG1--&gt;&lt;/p&gt;

&lt;p&gt;Ура, свершилось? Прямой доступ к машинным кодам прямо из браузера?&lt;/p&gt;

&lt;p&gt;Нет, не совсем так. Простые компилируемые в машинные коды программы на таких языках, как Ada и Delphi, всё ещё остаются шустрее. И вот, почему.&lt;/p&gt;

&lt;p&gt;$CUT$&lt;/p&gt;

&lt;h1&gt;Память&lt;/h1&gt;

&lt;p&gt;Память WebAssembly, &amp;mdash; это массив байт ограниченного размера с возможностью роста, плюс набор переменных модулей, вклад которых незначителен. Память настоящей программы, &amp;mdash; это виртуальная память большого размера, например, 2Гб.&lt;/p&gt;

&lt;h2&gt;Сегменты данных&lt;/h2&gt;

&lt;p&gt;Чтобы загрузить модуль WebAssembly со встроенным блоком памяти, надо &lt;strong&gt;скопировать&lt;/strong&gt; все байты в массив памяти WebAssembly. Если открыть несколько вкладок одного сайта, в каждой вкладке загрузится своя копия всех блоков памяти&amp;nbsp;WebAssembly (если только не прибегать к ухищрениям с opener, тянущим на кандидатскую).&amp;nbsp;Чтоб загрузить исполняемый или динамический модуль обычной программы, надо &lt;strong&gt;спроецировать&lt;/strong&gt; страницы памяти с диска в виртуальную память. Пока страницы памяти не потребуются, их можно даже не грузить. Можно прочитать в оперативную память и разделить между всеми экземплярами программы. Или между всеми программами, загрузившими одну и ту&amp;nbsp;же динамическую библиотеку. Можно&amp;nbsp;&lt;strong&gt;спроецировать&lt;/strong&gt; страницы памяти в режиме только для чтения, для констант, и тогда такие страницы точно общие. Можно&amp;nbsp;&lt;strong&gt;спроецировать&lt;/strong&gt; страницы памяти в режиме копирования при записи. Пока ничего не изменилось, страницы памяти общие для нескольких программ. Для WebAssembly эти прелести виртуальной памяти недоступны.&lt;/p&gt;

&lt;h2&gt;Стеки&lt;/h2&gt;

&lt;p&gt;Модулям WebAssembly доступен неадресуемый стек, который может быть достаточно просторным, и часто приходится выделять искусственный стек в памяти WebAssembly. Вся выделенная память WebAssembly является настоящей, то есть, дорогой. Обычные программы выделяют не память, а виртуальные адреса для стека, и уже потом в этих адресах постранично выделяется память по мере необходимости. Виртуальное адресное пространство позволяет удобно зарезервировать большое пространство адресов для стека, а всё оно может так и не понадобиться, и страницы выделены для него не будут.&lt;/p&gt;

&lt;h1&gt;Исполняемый код&lt;/h1&gt;

&lt;p&gt;Модули WebAssembly на самом деле не в машинных кодах, а чтобы их перевести, требуется время при каждой загрузке. Время можно экономить, если положиться на кеширование машинных кодов, но для этого нужно загружать чётко определённым образом, и уже не все возможности WebAssembly легко доступны.&lt;/p&gt;

&lt;p&gt;Обычные программы уже в машинных кодах, и их код проецируется страницами в виртуальную память.&lt;/p&gt;

&lt;h2&gt;Косвенные вызовы&lt;/h2&gt;

&lt;p&gt;Обычной программе почти ничего не стоит ссылаться на любые свои байты, в том числе на адреса функций. В WebAssembly каждая функция, которую можно вызвать косвенно, занимает место в массиве косвенно вызываемых функций. И, например, при загрузке динамической библиотеки требуется копировать новые функции в общий массив. Чем их больше, тем дольше обработка.&lt;/p&gt;

&lt;p&gt;В WebAssembly в одном массиве могут находиться функции только с одинаковой сигнатурой вызова. Значит, чтобы подключить динамическую библиотеку, в которой разные сигнатуры, нужно отдельно работать с каждым таким массивом.&lt;/p&gt;

&lt;p&gt;В некоторых компиляторах для простоты индексы общие. То есть, массивов много, но в большинстве массивов заглушка с ошибкой, и только в тех ячейках, где совпадение сигнатуры, настоящая ссылка на косвенно вызываемую функцию. Но тогда нужно обслуживать несколько преимущественно пустых массивов. Либо можно все массивы компактифицировать, но тогда весьма усложняются релокации.&lt;/p&gt;

&lt;h1&gt;Релокации&lt;/h1&gt;

&lt;p&gt;Релокация, &amp;mdash; это загрузка модуля, обычно динамической библиотеки, по её &amp;laquo;не основному&amp;raquo; базовому адресу. У обычной программы это хорошо поддержанная операция. Надо производить смещение всего лишь по одному базовому адресу, ведь код и данные двигаются синхронно. В некоторых операционных системах имеется система кеширования перебазированных библиотек, так что их можно подгружать, проецируя страницы с диска.&lt;/p&gt;

&lt;p&gt;В WebAssembly релокации производятся как минимум по двум &amp;laquo;адресам&amp;raquo;. Это собственно адрес сегмента данных в памяти WebAssembly, и также начальный индекс косвенно вызываемых функций. А если применяется компактное выделение массивов функций разной сигнатуры, то сколько сигнатур, столько и дополнительных базовых адресов релокаций.&lt;/p&gt;

&lt;h1&gt;Многопоточность&lt;/h1&gt;

&lt;p&gt;Обычные программы достаточно непринуждённо могут запускать несколько потоков. Программы на WebAssembly для подлинной многопоточности должны использовать такой инструмент, как Worker, и передать экземплярам массив&amp;nbsp;Wasm.Memory, созданный с флагом shared: true. Использование этого флага требует ограничить сверху максимально доступную память, чего не происходит в обычных программах.&lt;/p&gt;

&lt;p&gt;Также начинаются довольно весёлые проблемы с динамической загрузкой библиотек. Разные Worker друг от друга изолированы. Да, они могут обменяться сообщениями между собой и с Window, чтобы обрести общую Wasm.Memory, но программа на этом не заканчивается. Кроме данных ещё нужен исполняемый код, а он у каждого Worker свой. Чтобы создать иллюзию обычной многопоточной программы, нужно в каждом Worker одинаковым образом грузить все модули, и чтобы у них у всех было одинаковое видение всех релокаций.&lt;/p&gt;

&lt;p&gt;Гипотетически модули могут быть заменены на сервере прямо в тот момент, когда Worker их пытается грузить, и у&amp;nbsp;Worker загрузится своя версия модуля. Чтобы с этим бороться, можно сами загруженные WebAssembly сохранять как Blob и передавать в Worker, чтобы точно загрузилось то, что нужно. Но такие усложнения часто ведут к тому, что ломается стандартное кеширование исполняемого кода. Куда ни кинь, всюду клин.&lt;/p&gt;

&lt;h1&gt;Итог&lt;/h1&gt;

&lt;p&gt;Компилировать обычные программы по-прежнему имеет смысл. Разрыв между обычными программами и WebAssembly по использованию ресурсов велик, и трудно представить, чтобы он был сокращён. Архитектуру WebAssembly ещё требуется радикально поменять, и всё равно она останется далеко позади.&lt;/p&gt;

&lt;p&gt;Из-за сложностей поддержки динамических библиотек компиляторы часто создают замкнутые на себя статические модули, не раскрывающие потенциал ни обычных разделяемых библиотек, ни даже WebAssembly.&lt;/p&gt;

&lt;p&gt;Тем не менее, поддержка WebAssembly имеет важный смысл. Чем меньше кликов, тем выше конверсия.&amp;nbsp;WebAssembly нужен для &amp;laquo;малокликабельных&amp;raquo; версий программы. Для того, чтобы заманить скачать полноценную быструю версию программы.&lt;/p&gt;

&lt;p&gt;У JavaScript-&amp;laquo;программ&amp;raquo; преимущества устанавливаемых версий просматриваются с большим трудом. Программы для WebAssembly можно так переносимо писать, что у них будут быстрые родные версии, не требующие встроенного браузера.&lt;/p&gt;</content:encoded>
			<link>https://webassembly.su/blog/webassembly_tjazhelee_assemblera/2024-03-20-1</link>
			<dc:creator>OCTAGRAM</dc:creator>
			<guid>https://webassembly.su/blog/webassembly_tjazhelee_assemblera/2024-03-20-1</guid>
			<pubDate>Wed, 20 Mar 2024 18:03:02 GMT</pubDate>
		</item>
	</channel>
</rss>