Подтвердить что ты не робот

Могу ли я остановить .NET 4 с выполнением устранения хвостового вызова?

Мы переносим приложение в .NET 4.0 (с версии 3.5). Одна из проблем, с которыми мы сталкиваемся, воспроизводится только в очень специфических условиях:

  • Только в сборке Release
  • Только с включенной оптимизацией и/или информацией об отладке, установленной только для pdb.

Под этим я подразумеваю, что если я отключу оптимизацию и задаю полную информацию об отладке, проблема исчезнет.

Этот код отлично работает на .NET 3.5, в режиме Release с оптимизацией и т.д. включен и длится долгое время.

Я действительно не хочу предлагать, чтобы в компиляторе С# была ошибка, так что действительно мой вопрос: есть ли какие-либо методы, которые я могу использовать для отслеживания того, что мы можем делать неправильно, чтобы вызвать неправильную оптимизацию?

Я пытаюсь сузить эту проблему до небольшого тестового примера, чтобы опубликовать здесь код.

Edit:

Я обнаружил проблему следующим образом:

У нас есть этот код в конструкторе формы:

public ConnectionForm()
{
    LocalControlUtil.Configure("ConnectionForm", "Username", usernameLabel);
    LocalControlUtil.Configure("ConnectionForm", "Password", passwordLabel);
    LocalControlUtil.Configure("ConnectionForm", "Domain", domainLabel);
    LocalControlUtil.Configure("ConnectionForm", "Cancel", cancelButton);
    LocalControlUtil.Configure("ConnectionForm", "OK", okButton);
}

Эти вызовы относятся к некоторому пользовательскому коду локализации. Конструктор для этой формы вызывается из другой сборки. Метод LocalControlUtil.Configure вызывает Assembly.GetCallingAssembly(), который возвращает правильное значение для всех вышеуказанных вызовов, кроме последнего.

Я могу изменить порядок строк выше, добавить новые или удалить текущие, и каждый раз, когда это последняя строка, которая не работает.

Я предполагаю, что это JIT, вставляющий последний вызов метода в место, где был вызван конструктор (в другой сборке). Добавление [MethodImpl(MethodImplOptions.NoInlining)] в конструктор выше устраняет проблему.

Кто-нибудь знает, почему это происходит? Мне кажется странным, что последняя строка может быть только встроена. Это новое поведение в .NET 4.0?

Изменить 2:

Я сузил это сейчас до устранения хвостового вызова, я предполагаю, что вызванный новый хвост в .NET 4.

В приведенном выше коде последний вызов LocalControlUtil.Configure в конструкторе исключается и помещается в вызывающий метод, который находится в другой сборке. Поскольку метод вызывает Assembly.GetCallingAssembly, мы не получаем правильную сборку назад.

Есть ли способ остановить компилятор (или JIT или что-то в этом роде) от устранения хвостового вызова?

4b9b3361

Ответ 1

Нет, вы не можете.

.NET 4.0 оптимизирует больше хвостов-вызовов, чем 3.5, что хорошо. Наш код был сумасшедшим-глупым.

Ответ 2

Я бы просто добавил это в комментарий, если бы он не слишком долго, но вы пробовали:

public ConnectionForm()
{
  try
  {
    LocalControlUtil.Configure("ConnectionForm", "Username", usernameLabel);
    LocalControlUtil.Configure("ConnectionForm", "Password", passwordLabel);
    LocalControlUtil.Configure("ConnectionForm", "Domain", domainLabel);
    LocalControlUtil.Configure("ConnectionForm", "Cancel", cancelButton);
    LocalControlUtil.Configure("ConnectionForm", "OK", okButton);
  }
  catch
  {
    throw;
  }
}

Тот факт, что генерируется любое исключение, делает это в значительной степени нулевым изменением в терминах написанного кода, но границы try-catch часто предотвращают оптимизацию со стороны компилятора и дрожания.

Ответ 3

Я думаю, что вы уже на правильном пути для поиска проблемы... Сужение ее до самого маленького тестового примера - почти всегда отличный первый шаг.

Следующим будет сравнение IL, сгенерированного для каждой версии, в виде Reflector. Чтение ИЛ является нетривиальным (если у вас нет достаточного опыта), поэтому важно минимизировать количество кода, которое вам нужно просмотреть.

ОБНОВЛЕНИЕ: Я подумал об этом еще немного, и если проблема не заметна на уровне IL, это может быть на уровне JIT (Just In Time), что значительно сложнее отлаживать. Мне никогда не приходилось работать на этом уровне, поэтому у меня нет понимания этой части проблемы (если дело доходит до этого).