По-перше, прошу вибачення за тривалість цього питання.
Я автор IronScheme . Останнім часом я наполегливо працюю над тим, щоб надсилати гідну інформацію про налагодження, щоб я міг використовувати "рідний" .NET налагоджувач.
Хоча це частково успішно, я стикаюся з деякими проблемами з прорізуванням зубів.
Перша проблема пов'язана з кроком.
Через те, що схема є мовою вираження, все має тенденцію до загортання в дужках, на відміну від основних .NET мов, які, здається, засновані на заяві (або рядку).
Вихідний код (Схема) виглядає так:
(define (baz x)
(cond
[(null? x)
x]
[(pair? x)
(car x)]
[else
(assertion-violation #f "nooo" x)]))
Я спеціально виклав кожен вираз у новому рядку.
Випромінюваний код перетворюється на C # (через ILSpy):
public static object ::baz(object x)
{
if (x == null)
{
return x;
}
if (x is Cons)
{
return Builtins.Car(x);
}
return #.ironscheme.exceptions::assertion-violation+(
RuntimeHelpers.False, "nooo", Builtins.List(x));
}
Як бачите, досить просто.
Примітка: Якщо код перетворився на умовний вираз (? :) у C #, вся справа була б лише одним кроком налагодження, майте це на увазі.
Ось вихід IL із номерами джерел та рядків:
.method public static object '::baz'(object x) cil managed
{
// Code size 56 (0x38)
.maxstack 6
.line 15,15 : 1,2 ''
//000014:
//000015: (define (baz x)
IL_0000: nop
.line 17,17 : 6,15 ''
//000016: (cond
//000017: [(null? x)
IL_0001: ldarg.0
IL_0002: brtrue IL_0009
.line 18,18 : 7,8 ''
//000018: x]
IL_0007: ldarg.0
IL_0008: ret
.line 19,19 : 6,15 ''
//000019: [(pair? x)
.line 19,19 : 6,15 ''
IL_0009: ldarg.0
IL_000a: isinst [IronScheme]IronScheme.Runtime.Cons
IL_000f: ldnull
IL_0010: cgt.un
IL_0012: brfalse IL_0020
IL_0017: ldarg.0
.line 20,20 : 7,14 ''
//000020: (car x)]
IL_0018: tail.
IL_001a: call object [IronScheme]IronScheme.Runtime.Builtins::Car(object)
IL_001f: ret
IL_0020: ldsfld object
[Microsoft.Scripting]Microsoft.Scripting.RuntimeHelpers::False
IL_0025: ldstr "nooo"
IL_002a: ldarg.0
IL_002b: call object [IronScheme]IronScheme.Runtime.Builtins::List(object)
.line 22,22 : 7,40 ''
//000021: [else
//000022: (assertion-violation #f "nooo" x)]))
IL_0030: tail.
IL_0032: call object [ironscheme.boot]#::
'ironscheme.exceptions::assertion-violation+'(object,object,object)
IL_0037: ret
} // end of method 'eval-core(033)'::'::baz'
Примітка. Щоб запобігти простому виділенню налагоджувача всього методу, я вказую точку введення методу лише на 1 стовпчик.
Як бачимо, кожен вираз правильно відображається у рядку.
Тепер проблема з кроком (перевірена на VS2010, але та сама / аналогічна проблема у VS2008):
Вони IgnoreSymbolStoreSequencePoints
не застосовуються.
- Викличте baz з null arg, він працює правильно. (null? x) з наступним x.
- Викличте baz за допомогою аргументу аргументу, він працює правильно. (null? x) тоді (пара? x) тоді (автомобіль x).
- Викликати baz з іншими аргументами, це не вдається. (null? x) тоді (пара? x), тоді (автомобіль x), тоді (твердження-порушення ...).
При застосуванні IgnoreSymbolStoreSequencePoints
(як рекомендовано):
- Викличте baz з null arg, він працює правильно. (null? x) з наступним x.
- Зателефонуйте до baz з конс-аргом, це не вдається. (null? x) тоді (пара? x).
- Викликати baz з іншими аргументами, це не вдається. (null? x) тоді (пара? x), тоді (автомобіль x), тоді (твердження-порушення ...).
Я також знаходжу в цьому режимі, що деякі рядки (не показані тут) неправильно виділені, вони відключені на 1.
Ось кілька ідей, які можуть бути причинами:
- Хвостові дзвінки плутають налагоджувач
- Місця, що перекриваються (тут не показано) плутають налагоджувач (це робить дуже добре при встановленні точки перерви)
- ????
Друга, але також серйозна проблема - це те, що в деяких випадках налагоджувач не в змозі зламати / вдарити точки прориву.
Єдине місце, де я можу змусити налагоджувач правильно (і стійко) пробиватися, - це точка введення методу.
Ситуація стає трохи кращою, коли IgnoreSymbolStoreSequencePoints
її не застосовують.
Висновок
Можливо, налагоджувач VS - це просто баггі :(
Список літератури:
Оновлення 1:
Mdbg не працює для 64-бітних збірок. Отже, це поза. У мене немає більше 32-бітних машин для перевірки. Оновлення: Я впевнений, що це не велика проблема, чи має хтось виправлення? Редагувати: Так, нерозумно, просто запустіть mdbg під командним рядком x64 :)
Оновлення 2:
Я створив додаток C # і спробував розрізати інформацію про рядок.
Мої висновки:
- Після будь-якої
brXXX
інструкції потрібно мати точку послідовності (якщо вона не дійсна, так само "#line hidden", виберіть anop
). - Перед будь-якою
brXXX
інструкцією виправте "#line hidden" та "a"nop
.
Застосовуючи це, однак не вирішує проблеми (поодинці?).
Але додаючи наступне, дає бажаний результат :)
- Після
ret
цього виведіть "#line hidden" та anop
.
Для цього використовується режим, коли IgnoreSymbolStoreSequencePoints
він не застосовується. При застосуванні деякі кроки все ще пропускаються :(
Ось вихід IL, коли було застосовано вище:
.method public static object '::baz'(object x) cil managed
{
// Code size 63 (0x3f)
.maxstack 6
.line 15,15 : 1,2 ''
IL_0000: nop
.line 17,17 : 6,15 ''
IL_0001: ldarg.0
.line 16707566,16707566 : 0,0 ''
IL_0002: nop
IL_0003: brtrue IL_000c
.line 16707566,16707566 : 0,0 ''
IL_0008: nop
.line 18,18 : 7,8 ''
IL_0009: ldarg.0
IL_000a: ret
.line 16707566,16707566 : 0,0 ''
IL_000b: nop
.line 19,19 : 6,15 ''
.line 19,19 : 6,15 ''
IL_000c: ldarg.0
IL_000d: isinst [IronScheme]IronScheme.Runtime.Cons
IL_0012: ldnull
IL_0013: cgt.un
.line 16707566,16707566 : 0,0 ''
IL_0015: nop
IL_0016: brfalse IL_0026
.line 16707566,16707566 : 0,0 ''
IL_001b: nop
IL_001c: ldarg.0
.line 20,20 : 7,14 ''
IL_001d: tail.
IL_001f: call object [IronScheme]IronScheme.Runtime.Builtins::Car(object)
IL_0024: ret
.line 16707566,16707566 : 0,0 ''
IL_0025: nop
IL_0026: ldsfld object
[Microsoft.Scripting]Microsoft.Scripting.RuntimeHelpers::False
IL_002b: ldstr "nooo"
IL_0030: ldarg.0
IL_0031: call object [IronScheme]IronScheme.Runtime.Builtins::List(object)
.line 22,22 : 7,40 ''
IL_0036: tail.
IL_0038: call object [ironscheme.boot]#::
'ironscheme.exceptions::assertion-violation+'(object,object,object)
IL_003d: ret
.line 16707566,16707566 : 0,0 ''
IL_003e: nop
} // end of method 'eval-core(033)'::'::baz'
Оновлення 3:
Проблема з вищезазначеним "напівсправлення". Перифікуйте помилки у звітах щодо всіх методів із-за nop
після ret
. Я не розумію проблему насправді. Як можна nop
перевірити перерву після a ret
. Це як мертвий код (за винятком того, що це НЕ навіть код) ... Ну добре, експерименти продовжуються.
Оновлення 4:
Повернувшись вдома зараз, видалили неперевірений код, який працює на VS2008, і все набагато гірше. Можливо, запуск неперевіреного коду заради правильної налагодження може бути відповіддю. У режимі "випуску" весь вихід все ще може бути перевірений.
Оновлення 5:
Зараз я вирішив, що моя вище ідея є єдиним життєздатним варіантом на даний момент. Незважаючи на те, що згенерований код не підтверджується, я ще не міг знайти жодного VerificationException
. Я не знаю, який вплив буде на кінцевого користувача за цим сценарієм.
Як бонус, моє друге питання також було вирішено. :)
Ось невеликий скріншот того, з чим я закінчився. Він вражає точки прориву, робить належні кроки (в / в / над) тощо. Загалом, бажаний ефект.
Я, однак, досі не сприймаю це як спосіб це зробити. Мені це здається надмірно хитким. Мати підтвердження справжнього питання було б непогано.
Оновлення 6:
Щойно відбулася зміна тестування коду на VS2010, мабуть, є деякі проблеми:
Перший виклик зараз не йде правильно. (ствердження-порушення ...) потрапляє. В інших випадках чудово працює.Деякий старий код видав непотрібні позиції. Видалений код, працює як очікувалося. :)- Якщо серйозніше, точки прориву не вдаються під час другого виклику програми (використання компіляції в пам'яті, демпінгова збірка для подачі файлів, здається, знову зробить точки пробивання щасливими).
Обидва ці випадки працюють нормально за VS2008. Основна відмінність полягає в тому, що під VS2010 вся програма складена для .NET 4 і під VS2008, компілюється в .NET 2. Обидва працюють 64-бітними.
Оновлення 7:
Як згадувалося, у мене mdbg працює під 64-розрядною версією. На жаль, у нього також є проблема точки перерви, де вона не може зламатися, якщо я повторно програму (це означає, що вона перекомпілюється, тому не використовуючи ту саму збірку, але все ж використовуючи те саме джерело).
Оновлення 8:
Я зареєстрував помилку на сайті MS Connect щодо проблеми точки розриву.
Оновлення: виправлено
Оновлення 9:
Після довгого роздуму, здається, єдиний спосіб зробити налагоджувач щасливим - це зробити SSA, тому кожен крок може бути ізольованим та послідовним. Я ще маю довести це поняття. Але це здається логічним. Очевидно, що очищення темпів із SSA призведе до налагодження налагодження, але це легко переключити, а залишення їх не має великих витрат.
nop
кроку не вдасться (я ще раз переконаюсь у цьому). Думаю, що це - жертва. Це не так, як VS може працювати навіть без прав адміністратора :) Btw за допомогою Reflection.Emit через DLR (дуже зламаний ранній розгалужений).