Скажите, а почему gcc поменял местами эти инструкции, если указатель кадра и указатель стека все равно не приравниваются (тут, в этом куске по крайней мере). Т.е. и rbp и rsp определены заранее, раз компилятор так запросто опирается на rbp до rsp -> rbp.
В чем оптимизация, как можо что-то выиграть, записывая в стек до изменения указателя? Так лучше загружается конвейер?
Если бы (лучше знаком с IA32), было бы так:
sub esp, 64
mov ebp, esp
mov [ebp + 12], xyz
все бы три инструкции выполнялись последовательно, т.к. каждая последующая зависит от результатов предыдущей. Если (не помню точно ни по тактам, ни по спариванию в разных пайпах) пересылка регистр-регистр, выполняется за 1 такт, а вычитание — за большее кол-во, был бы смысл менять местами, заранее прибавляя к ebp константу с учетом того, что esp подвинется позже.
XP — допиленная 2000, но рядовой пользователь тут ни при чем. Ядра у них немного разные, например, различны способы входа в ядро —
через прерывание или sysenter. XP — Развитие 2000.
А сама двака существовала на ядре NT во времена 98 преимущественно на серверах
Не путайте W2000 и W2000 Server.
Так что линейка 98 — Me — Xp — Vista — 7 — 8 -9 правильная.
Нет, не правильная.
98-Me-2000-XP->
А Windows NT кто-то помнит ещё? :)
Помнит. XP или 7 — NT. Например, Windows 7 = Windows NT 6.1
На изображении мы видим 2 ветви и по 3 файла в каждой папке.
Извините, пожалуйста, но я у впор не вижу 2 ветви на изображении.
Есть три уровня в дереве (слоя), (ну, или два уровня, если считать корень обособленной единицей), у каждого узла — по три ветви.
1985 Quick Basic
1987… В отличие от большинства реализаций Бейсика того периода, Turbo Basic был полным компилятором, генерировавшим родной код для MS-DOS.
Quick Basic — как раз компилируемый. Интерпретируемый — QBasic.
1.00 — 5.25" version was released on 8/18/85. In 1985 Microsoft released a new version of their command line PC BASIC compiler, and called it QuickBasic.
В каждом конкретном месте надо смотреть отдельно. Я вижу в нашем коде случаи, когда безусловный переход, при правильно названной метке, более читаем, чем разбивка на процедуры. Но таких случаев, конечно, мизер.
Каждому инструменту — свое применение. Ничто не панацея. Иногда выгодно использовать такой вариант, иногда — другой, иногда комбинировать. Использование искусственных исключений для сообщений об ошибках — достаточно распространенная практика. Это очень удобно, когда надо «подняться» на 3-4 уровня вверх, попутно освобождая ресурсы, и там, наверху, все обработать (именно в случае ошибки). В противном случае на каждом уровне вам надо будет иметь обертку для ошибки.
Можно сравнить оба подхода в коде. Этого, кстати, очень не хватает в дискуссии в комментариях — на пальцах обсуждать сложно.
Все проблемы связанные с обработкой исключений, из-за которых и появляются статьи вроде этой
По мне, часть проблем в статье — надуманные, если не сказать большего.
отсутствие корректной обработки ошибок
Почему передача ошибок (только тогда, когда это нужно — если мы не просто возвращаем состояние «удача-провал», а имеем ошибку, которая потребует дополнительных действий) исключениями — это некорректно?
Просто пытаюсь понять вашу точку зрения — почему это неправильно, почему это некорректно и как там с раскруткой стека?
Вы несколько раз употребили оборот вроде «это неправильно», причем, как мне кажется, безосновательно — поэтому я и интересуюсь. Не в плане ругани, а для того, чтобы прояснить для себя вашу позицию, узнать, возможно, что-то новое.
Да, механизм исключений более тяжеловесный. Да, не для любой ошибки применим. Так ли уж велика избыточность? Особенно, если обработка ошибки подразумевает дополнительную работу вроде записи лога, что уже отнимает время на ввод-вывод.
Вычитание отрицательного числа учитывается?
Если у нас есть различие ± в самом числе, то как его трактовать — всего лишь наш выбор. А так, в допкоде — при вычитании мы используем тот же ADD, т.е. ассемблер как раз проще. Подготовка допкода — всего навсего инвертирование + добавление 2х. Хотя да, для релейной машины это, наверно, тяжеловато будет, вы правы. Вот если бы линейка отложенного переноса была… Но тогда 4 пар контактов не хватит.
Вообще, спасибо за статью, очень интересно.
Под «и есть такой объект» я не подразумевал тождественности. Я имел в виду — «одна из реализаций».
Что именно вы подразумеваете под раскручиванием стека? Этому словосочетанию разными людьми придаются разные смыслы — от сворачивания обычного стека до обработки цепочки исключений.
Нет, конечно, если Вы мазохист, то Вы можете сэмулировать корректную обработку ошибок нарисовав отдельный try/catch вокруг вызова каждой функции, которая теоретически может вернуть ошибку…
Искусственные исключения позволяют избежать ситуации, при которой на 1 строчку-вызов функции приходится 2 для обработки ошибки (и освобождения ресурсов, например), что приводит к нечитаемости.
Искусственные исключения не несут почти никакой избыточности, при этом одинаково удобно обрабатываются ошибки и сохраняется целостность ресурсов, например (выделение буфера/освобождение при ошибке в двух точках, без множества переходов и пр.
Естественно, и при этом подходе — «на практике» — наверх приходит и низкоуровневое описание, иначе откуда бы взялась эта информация. И в случае, кстати, возврата ошибки искусственным исключением, при создании «общего» класса «ошибка выкачки» с деталями в приложенном сообщении, это решается элегантно.
Кстати, насчет структурного программирования и GOTO: классно затроллил Дейкстру Кнут, выпустив статью «Структурное программирование с использованием оператора GOTO». Его доводы выглядят не менее убедительно, чем Д.
например, из вызванной функции мы получили ошибку DNS «host not found», а выше возвращаем ошибку «не могу скачать url (host not found)
Не согласен. Допустим, на более высоком уровне стоит логгер. И мне при отладке намного полезнее знать, что произошла вот эта вот конкретная системная ошибка, а не «извините, что-то пошло не так».
В чем оптимизация, как можо что-то выиграть, записывая в стек до изменения указателя? Так лучше загружается конвейер?
Если бы (лучше знаком с IA32), было бы так:
sub esp, 64
mov ebp, esp
mov [ebp + 12], xyz
все бы три инструкции выполнялись последовательно, т.к. каждая последующая зависит от результатов предыдущей. Если (не помню точно ни по тактам, ни по спариванию в разных пайпах) пересылка регистр-регистр, выполняется за 1 такт, а вычитание — за большее кол-во, был бы смысл менять местами, заранее прибавляя к ebp константу с учетом того, что esp подвинется позже.
Но в обсуждаемом куске? Я что-то упускаю?
XP — допиленная 2000, но рядовой пользователь тут ни при чем. Ядра у них немного разные, например, различны способы входа в ядро —
через прерывание или sysenter. XP — Развитие 2000.
Не путайте W2000 и W2000 Server.
Нет, не правильная.
98-Me-2000-XP->
Помнит. XP или 7 — NT. Например, Windows 7 = Windows NT 6.1
Извините, пожалуйста, но я у впор не вижу 2 ветви на изображении.
Есть три уровня в дереве (слоя), (ну, или два уровня, если считать корень обособленной единицей), у каждого узла — по три ветви.
Quick Basic — как раз компилируемый. Интерпретируемый — QBasic.
Тут история МС бейсиков
Можно сравнить оба подхода в коде. Этого, кстати, очень не хватает в дискуссии в комментариях — на пальцах обсуждать сложно.
По мне, часть проблем в статье — надуманные, если не сказать большего.
Почему передача ошибок (только тогда, когда это нужно — если мы не просто возвращаем состояние «удача-провал», а имеем ошибку, которая потребует дополнительных действий) исключениями — это некорректно?
Просто пытаюсь понять вашу точку зрения — почему это неправильно, почему это некорректно и как там с раскруткой стека?
Вы несколько раз употребили оборот вроде «это неправильно», причем, как мне кажется, безосновательно — поэтому я и интересуюсь. Не в плане ругани, а для того, чтобы прояснить для себя вашу позицию, узнать, возможно, что-то новое.
Да, механизм исключений более тяжеловесный. Да, не для любой ошибки применим. Так ли уж велика избыточность? Особенно, если обработка ошибки подразумевает дополнительную работу вроде записи лога, что уже отнимает время на ввод-вывод.
Если у нас есть различие ± в самом числе, то как его трактовать — всего лишь наш выбор. А так, в допкоде — при вычитании мы используем тот же ADD, т.е. ассемблер как раз проще. Подготовка допкода — всего навсего инвертирование + добавление 2х. Хотя да, для релейной машины это, наверно, тяжеловато будет, вы правы. Вот если бы линейка отложенного переноса была… Но тогда 4 пар контактов не хватит.
Вообще, спасибо за статью, очень интересно.
Что именно вы подразумеваете под раскручиванием стека? Этому словосочетанию разными людьми придаются разные смыслы — от сворачивания обычного стека до обработки цепочки исключений.
Искусственные исключения позволяют избежать ситуации, при которой на 1 строчку-вызов функции приходится 2 для обработки ошибки (и освобождения ресурсов, например), что приводит к нечитаемости.
Искусственные исключения не несут почти никакой избыточности, при этом одинаково удобно обрабатываются ошибки и сохраняется целостность ресурсов, например (выделение буфера/освобождение при ошибке в двух точках, без множества переходов и пр.
«Свое» исключение и есть такой объект, обертка try...<в разных языках свое> — обработчик такой ошибки. Overhead на установку SEH цепочки копеечный.
Не согласен. Допустим, на более высоком уровне стоит логгер. И мне при отладке намного полезнее знать, что произошла вот эта вот конкретная системная ошибка, а не «извините, что-то пошло не так».