пятница, 10 апреля 2015 г.

Чем меня порадовала ХЕ8

В последнее время я все чаще задумываюсь о смысле апдейта текущей версии Delphi на более новую. Есть ли в этом необходимость?
С учетом, что я разрабатываю 32 битные приложения только под Win - вся эта петрушка в виде возможности разработки под Андроид или iOS прямо на Delphi, ну... скажем так — не сильно востребована.
А вот что более востребовано — так это стабильная работа среды, отсутствие ошибок при работе с дженериками/лямдами и всем тем "синтаксическим сахаром", который внедряется уже какой год.
Вы будете смеяться, но я однажды вообще от инлайнов отказался по многим причинам, в частности одна из них была в том, что кодогенератор выдавал абсолютно невалидный асм код в определенных ситуациях, абсолютно переиначивая всю логику работы inline функции (банально не тот результат возвращала). Кажется это было на 2010 или ХЕ первой.

Впрочем посмотрим что мы имеем сейчас.



Краткий перечень нововведений:
  • GetIt package manager for seamless installation of components 
  • DUnitX support 
  • Version Insight support for Mercurial, and improved support for Git and Subversion 
  • IDE configuration migration tool 
  • Faster CHM help 
  • Start here page redesign 
  • Project statistics information 
  • Clipboard history 
  • Multi-paste support 
  • Stack bookmarks 
  • Smart keys 
  • Parenthesis matching 
  • Code structural highlight 
  • Castalia refactorings 
  • Editor selection expansion 
  • Flow controls highlighting 
  • Code navigation toolbar 
  • Smart symbol search 
  • Code analysis to track quality

GetIt - забавная такая приблуда, позволяющая оперативно ставить сторонние пакеты. Но вот вопрос:
А как часто вы ставите сторонние пакеты компонентов?
Лично я, только при переустановке дельфи ставлю VirtualStringTree, плюс раз в полгода обновляю DevExpress (зависит от того, как часто они сами родят новую версию).
Ничего против, конечно, не имею - но GetIt это просто фишка, не имеющая к процессу разработки никакого отношения.

DUnitX - ну, допустим, юниттестирование должно прививаться разработчикам.

Интеграция различных систем контроля версий (SVN/Git/HG - Mercurial).
Этот момент спорный - люди годами ими пользуются, в том числе и экспертами, которые уже умеют это все делать. Не факт что удачный ход.

Тоже относится и к Castalia - первый вопрос будет, для непривычного пользователя: как это отключить? (например вот так).

А что еще осталось?

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

Остальные фишки - да, интересны, но может взглянем на решарпер (продвинутое расширение IDE для C#) и его возможности? :)

Ну и какой сделаем вывод - все плохо?

А вот с этим будет нюанс и для раскрытия оного я процитирую своего коллегу: Алексея Казанцева.

program inline_bug;

{$APPTYPE CONSOLE}
{$OPTIMIZATION ON}
{$INLINE ON}

{$R *.res}

uses
  SysUtils;

type
  Utils = class
  type
    Namespace = class
      class function Comparestring(const ALeft, ARight: string) : Integer; static; inline;
      class function CompareText(const ALeft, ARight: string) : Integer; static; inline;
      class function Samestring(const ALeft, ARight: string; 
        ACaseSensitive : Boolean = True) : Boolean; static; inline;
    end;
  end;

{ Utils.NameSpace }

class function Utils.Namespace.Comparestring(const ALeft, ARight : System.string) : Integer;
begin
 Result := SysUtils.CompareStr(ALeft, ARight);
end;

class function Utils.Namespace.CompareText(const ALeft, ARight : string) : Integer;
begin
 Result := SysUtils.CompareText(ALeft, ARight);
end;

class function Utils.Namespace.Samestring(const ALeft, ARight : string; ACaseSensitive : Boolean) : Boolean;
begin
 if ACaseSensitive then
  Result := Utils.Namespace.Comparestring(ALeft, ARight) = 0
 else
  Result := Utils.Namespace.CompareText(ALeft, Aright) = 0;
end;

var
 S1, S2: string;
begin
 Utils.Namespace.Comparestring(S1, S2);
 Utils.Namespace.Samestring(S1, S2);
 S1 := '';
end.

Банально сравниваем две строки.
Но давайте посмотрим на кодогенерацию в продуктах до ХЕ включительно:

inline_bug.dpr.68: Utils.Namespace.CompareString(S1, S2);
0040915A 8B1524E24000     mov edx,[$0040e224]
00409160 A120E24000       mov eax,[$0040e220]
00409165 E8F2C7FFFF       call CompareStr
inline_bug.dpr.69: Utils.Namespace.SameString(S1, S2);
0040916A 8B1524E24000     mov edx,[$0040e224]
00409170 A120E24000       mov eax,[$0040e220]
00409175 E8E2C7FFFF       call CompareStr
0040917A 85C0             test eax,eax
0040917C 0F94C0           setz al

Абсолютно логичный код - никаких претензий, но посмотрим что будет под XE2:

inline_bug.dpr.68: Utils.Namespace.CompareString(S1, S2);
0041B3AB 8D45EC           lea eax,[ebp-$14]
0041B3AE 8B15D82E4200     mov edx,[$00422ed8]
0041B3B4 E84BA4FEFF       call @UStrLAsg
0041B3B9 8D45E8           lea eax,[ebp-$18]
0041B3BC 8B15DC2E4200     mov edx,[$00422edc]
0041B3C2 E83DA4FEFF       call @UStrLAsg
0041B3C7 8B55E8           mov edx,[ebp-$18]
0041B3CA 8B45EC           mov eax,[ebp-$14]
0041B3CD E8F28FFFFF       call CompareStr
inline_bug.dpr.69: Utils.Namespace.SameString(S1, S2);
0041B3D2 8D45E4           lea eax,[ebp-$1c]
0041B3D5 8B15D82E4200     mov edx,[$00422ed8]
0041B3DB E824A4FEFF       call @UStrLAsg
0041B3E0 8D45E0           lea eax,[ebp-$20]
0041B3E3 8B15DC2E4200     mov edx,[$00422edc]
0041B3E9 E816A4FEFF       call @UStrLAsg
0041B3EE 8D45DC           lea eax,[ebp-$24]
0041B3F1 8B55E4           mov edx,[ebp-$1c]
0041B3F4 E80BA4FEFF       call @UStrLAsg
0041B3F9 8D45D8           lea eax,[ebp-$28]
0041B3FC 8B55E0           mov edx,[ebp-$20]
0041B3FF E800A4FEFF       call @UStrLAsg
0041B404 8B55D8           mov edx,[ebp-$28]
0041B407 8B45DC           mov eax,[ebp-$24]
0041B40A E8B58FFFFF       call CompareStr
0041B40F 85C0             test eax,eax
0041B411 0F94C0           setz al

Страшно, но сейчас посмотрим что выдается под ХЕ4/ХЕ5:

inline_bug.dpr.45: Utils.Namespace.Comparestring(S1, S2);
0041A3E4 8D45EC           lea eax,[ebp-$14]
0041A3E7 8B15D81E4200     mov edx,[$00421ed8]
0041A3ED E8F2B6FEFF       call @UStrLAsg
0041A3F2 8D45E8           lea eax,[ebp-$18]
0041A3F5 8B15DC1E4200     mov edx,[$00421edc]
0041A3FB E8E4B6FEFF       call @UStrLAsg
0041A400 33C0             xor eax,eax
0041A402 55               push ebp
0041A403 683AA44100       push $0041a43a
0041A408 64FF30           push dword ptr fs:[eax]
0041A40B 648920           mov fs:[eax],esp
0041A40E 8B55E8           mov edx,[ebp-$18]
0041A411 8B45EC           mov eax,[ebp-$14]
0041A414 E8F782FFFF       call CompareStr
0041A419 8945CC           mov [ebp-$34],eax
0041A41C 33C0             xor eax,eax
0041A41E 5A               pop edx
0041A41F 59               pop ecx
0041A420 59               pop ecx
0041A421 648910           mov fs:[eax],edx
0041A424 6841A44100       push $0041a441
0041A429 8D45EC           lea eax,[ebp-$14]
0041A42C E897B3FEFF       call @UStrClr
0041A431 8D45E8           lea eax,[ebp-$18]
0041A434 E88FB3FEFF       call @UStrClr
0041A439 C3               ret 
0041A43A E9ADAAFEFF       jmp @HandleFinally
0041A43F EBE8             jmp $0041a429

inline_bug.dpr.46: Utils.Namespace.Samestring(S1, S2);
0041A441 8D45E4           lea eax,[ebp-$1c]
0041A444 8B15D81E4200     mov edx,[$00421ed8]
0041A44A E895B6FEFF       call @UStrLAsg
0041A44F 8D45E0           lea eax,[ebp-$20]
0041A452 8B15DC1E4200     mov edx,[$00421edc]
0041A458 E887B6FEFF       call @UStrLAsg
0041A45D 8D45DC           lea eax,[ebp-$24]
0041A460 E863B3FEFF       call @UStrClr
0041A465 8D45D8           lea eax,[ebp-$28]
0041A468 E85BB3FEFF       call @UStrClr
0041A46D 8D45D4           lea eax,[ebp-$2c]
0041A470 E853B3FEFF       call @UStrClr
0041A475 8D45D0           lea eax,[ebp-$30]
0041A478 E84BB3FEFF       call @UStrClr
0041A47D 33C0             xor eax,eax
0041A47F 55               push ebp
0041A480 6828A54100       push $0041a528
0041A485 64FF30           push dword ptr fs:[eax]
0041A488 648920           mov fs:[eax],esp
0041A48B 8D45DC           lea eax,[ebp-$24]
0041A48E 8B55E4           mov edx,[ebp-$1c]
0041A491 E84EB6FEFF       call @UStrLAsg
0041A496 8D45D8           lea eax,[ebp-$28]
0041A499 8B55E0           mov edx,[ebp-$20]
0041A49C E843B6FEFF       call @UStrLAsg
0041A4A1 33C0             xor eax,eax
0041A4A3 55               push ebp
0041A4A4 68DBA44100       push $0041a4db
0041A4A9 64FF30           push dword ptr fs:[eax]
0041A4AC 648920           mov fs:[eax],esp
0041A4AF 8B55D8           mov edx,[ebp-$28]
0041A4B2 8B45DC           mov eax,[ebp-$24]
0041A4B5 E85682FFFF       call CompareStr
0041A4BA 8945C4           mov [ebp-$3c],eax
0041A4BD 33C0             xor eax,eax
0041A4BF 5A               pop edx
0041A4C0 59               pop ecx
0041A4C1 59               pop ecx
0041A4C2 648910           mov fs:[eax],edx
0041A4C5 68E2A44100       push $0041a4e2
0041A4CA 8D45DC           lea eax,[ebp-$24]
0041A4CD E8F6B2FEFF       call @UStrClr
0041A4D2 8D45D8           lea eax,[ebp-$28]
0041A4D5 E8EEB2FEFF       call @UStrClr
0041A4DA C3               ret 
0041A4DB E90CAAFEFF       jmp @HandleFinally
0041A4E0 EBE8             jmp $0041a4ca
0041A4E2 837DC400         cmp dword ptr [ebp-$3c],$00
0041A4E6 0F9445CB         setz byte ptr [ebp-$35]
0041A4EA 33C0             xor eax,eax
0041A4EC 5A               pop edx
0041A4ED 59               pop ecx
0041A4EE 59               pop ecx
0041A4EF 648910           mov fs:[eax],edx
0041A4F2 682FA54100       push $0041a52f
0041A4F7 8D45E4           lea eax,[ebp-$1c]
0041A4FA E8C9B2FEFF       call @UStrClr
0041A4FF 8D45E0           lea eax,[ebp-$20]
0041A502 E8C1B2FEFF       call @UStrClr
0041A507 8D45DC           lea eax,[ebp-$24]
0041A50A E8B9B2FEFF       call @UStrClr
0041A50F 8D45D8           lea eax,[ebp-$28]
0041A512 E8B1B2FEFF       call @UStrClr
0041A517 8D45D4           lea eax,[ebp-$2c]
0041A51A E8A9B2FEFF       call @UStrClr
0041A51F 8D45D0           lea eax,[ebp-$30]
0041A522 E8A1B2FEFF       call @UStrClr
0041A527 C3               ret 
0041A528 E9BFA9FEFF       jmp @HandleFinally
0041A52D EBC8             jmp $0041a4f7
redsfds.dpr.47: S1 := '';
0041A52F B8D81E4200       mov eax,$00421ed8
0041A534 E88FB2FEFF       call @UStrClr

Впечатлились?
Вот и я тоже, впрочем я не оставлял надежды что когда-то все придет в норму.
И вот вышла ХЕ8 и я сразу попросил проверить данный код, и что вы думаете?

contest.dpr.68: Utils.Namespace.CompareString(S1, S2);
0041B49A 8B15C02E4200     mov edx,[$00422ec0]
0041B4A0 A1BC2E4200       mov eax,[$00422ebc]
0041B4A5 E8827CFFFF       call CompareStr
contest.dpr.69: Utils.Namespace.SameString(S1, S2);
0041B4AA 8B15C02E4200     mov edx,[$00422ec0]
0041B4B0 A1BC2E4200       mov eax,[$00422ebc]
0041B4B5 E8727CFFFF       call CompareStr
0041B4BA 85C0             test eax,eax
0041B4BC 0F94C0           setz al
contest.dpr.70: s1 := '';
0041B4BF B8BC2E4200       mov eax,$00422ebc
0041B4C4 E8A7A9FEFF       call @UStrClr

Бинго.
Кодогенератор отдали в правильные руки и он снова стал работать как нужно.
А еще поправили несколько ошибок в дженериках, критичных лично для меня, но это уже не суть.

Так вот вопрос, а почему ломали кодогенерацию столько версий подряд?
Через тернии к звездам? :)

Впрочем, теперь я уверен - на ХЕ8 переходить с ХЕ2 и выше стоит.

UPDATE:
Ан нет - поторопился.
В процессе тестов нашел интересный глюк, который не позволяет мне собрать проект. Причем билдится нормально, а на этапе компиляции происходит вот такое:


Впрочем, глюк не то чтобы интересный - глюк критический.

UPDATE2:
Накидаю несколько своих мыслей по поводу данной ошибки.
Завтра, конечно попробую выдать на гора что-то воспроизводящееся, но пока что просто суть.

Сейчас мы сидим на XE4, и на нем наблюдается следующие типы ошибок (на самом главном и достаточно большом проекте под полтора лямов строчек).
Если нажать F9 (просто компиляция) то может произойти:

  • либо Internal Error 
  • либо откроется какой либо модуль, к нему добавится пустая строчка в самом конце модуля и выведется сообщение что не могу данный модуль сохранить (как правило для модулей которые сидят в Programm Files).
  • либо - все будет хорошо (редкий случай).

Обходится это все обычным ребилдом проекта, после чего компиляция начинает работать нормально.

Началось это с перехода на ХЕ.
Подозреваю, что проблема из-за того что у нас очень большое количество модулей, ссылающихся друг на друга достаточно капитальное кол-во раз и где-то именно на анализе этих перекрестных ссылок линкер и начинает дурить.

В данном случае, билд проходит успешно, но при компиляции (жмаем F9) происходит вот такая вот рекурсивная беда.

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

UPDATE3:
На 24 миллионах строчек скомпилированного кода оно успокоилось :)


Выдав ошибку:


Однако ж - час компилилось.
Сурово.

UPDATE4:
Становится все интересней.
В рамках тестирования создал новый VCL проект и подключил к нему один из тестируемых модулей.
Результат компиляции:


Копаю дальше.

UPDATE5:
А еще установщик утверждает что 13 свободных гигабайт ему мало :))


18 комментариев:

  1. И все же, можно поподробнее об ошибках в дженериках? Раз уж вы их упомянули, раскройте тему до конца, плиз :)

    ОтветитьУдалить
    Ответы
    1. Рано еще, еще не все ошибки выявлены. Обновил пост, добавил видео "вечной компиляции проекта" :)

      Удалить
    2. Это надо срочно в qc(qp), авось к первому апдейту пофиксят

      Удалить
    3. Это если повезет и они смогут это воспроизвести...

      Удалить
    4. В качестве ответа, обновил текст статьи.

      Удалить
    5. Ждем новых отчетов о расследовании!!!

      Удалить
  2. У меня XE8 по сравнению с XE7 фиксит первые два пункта, упомянутые в Update2 статьи. Но добавляет зависание самой среды в режиме отладки. Не могу определить точных шагов для воспроизведения, но есть предположение, что глючит внутренний evaluator при отладке дженериков. Правда в XE7 у меня стоит IDE Fix Pack от Хаусладена...

    ОтветитьУдалить
  3. Охохо, похоже в процессе тестирования я умудрился убить не только ХЕ8, но и до кучи основную ХЕ4.
    Сам не понял, как так получилось, но - факт.
    Можно сказать - рабочий день начался удачно :)))

    ОтветитьУдалить
    Ответы
    1. Обновления для Windows не ставили?

      Удалить
    2. У людей тоже проблемы (читать отсюда и ниже):
      http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=190407&msg=17516531

      Удалить
    3. Ничего не ставил, машина вообще у меня не перезагружается месяцами, но факт есть факт. Что XE8 и самое интересное XE4 тоже падает при старте с ошибкой: "The program can't start because rtl220.bpl is missing from your computer. Try reinstalling the program to fix this problem. "

      Вообще ничего понять не могу.

      Удалить
    4. Оставлю в качестве напоминалки для самого себя. Чтобы починить ХЕ4 после такого вот "убития", нужно найти в "Моих документах" все упоминания о ХЕ8 (к примеру C:\Users\Public\Documents\Embarcadero\Studio\16.0) и переименовать папку 16.0 в любую другую. Инсталятору от ХЕ8 это не поможет, но хотя бы ХЕ4 будет запускаться правильно.

      Удалить
  4. Дмитрий Белькевич20 мая 2015 г. в 01:29

    К слову, попробовал код в XE6 - там уже так же, как в 2010, то есть - нормально собирается.

    ОтветитьУдалить
    Ответы
    1. Ага, я уже позже тоже проверил. Пофиксили кодогенерацию чуть раньше, но мы шестерку как-то мимо ушей пропустили, ибо там для нас не было ничего интересного :)

      Удалить
    2. Здравствуйте Александр, у меня такой вопрос по XE8 стоит ли сейчас переходить(вроде там апдейты есть)? почему меня предыдущие XE не радуют - это большой скомпилированный код EXEшник, изменилась ли ситуация?

      Удалить
    3. Я не проверял, поэтому сказать ничего не могу. Сейчас очень сильная нагрузка на работе, поэтому еще не скоро за это возьмусь.

      Удалить