Я думаю, что единственный определенный ответ могут дать люди, которые реализуют оптимизацию компилятора, как на стороне Roslyn, так и на стороне RyuJIT.
Поскольку вы используете .NET Core, вы, конечно, можетеПогрузитесь в исходный код и найдите ответ самостоятельно.Это будет ответом для конкретной версии компилятора.
Посмотрите на сгенерированный код IL для вашего фрагмента:
// int value = 0;
ldc.i4.0
stloc.0
// MemoryMarshal.CreateSpan(ref value, 1)
ldloca.s 0
ldc.i4.1
call valuetype System.Span`1<!!0> System.Runtime.InteropServices.MemoryMarshal::CreateSpan<int32>(!!0&, int32)
// the rest is omitted
Обратите внимание, что ldloca.s
код операции.Эта операция загружает адрес локальной переменной в стек оценки .
Хотя я не могу предоставить вам официальную ссылку, подтверждающую это, но я уверен, что и C #, и JITкомпиляторы не будут оптимизировать эту локальную переменную - только потому, что был использован ее адрес, поэтому есть вероятность, что эта локальная переменная будет видоизменена через ее адрес.
Если вы посмотрите на сгенерированный код сборки, вы увидите именно это:локальная переменная находится там и помещается в стек, она не является переменной только для регистров.
// int value = 0;
xor ecx,ecx
mov dword ptr [rsp+3Ch],ecx
WHILE_LOOP_START:
// ... do stuff
// effectively: if (value >= 0) goto WHILE_LOOP_START
cmp dword ptr [rsp+3Ch],0
jge WHILE_LOOP_START
Попробуйте написать код, который не выдает код операции ldloca.s
(например, просто ++value
в цикле), переменная value
, скорее всего, станет переменной только для регистров.
Если вы измените свой код таким образом, что value
никогда не записывается (кроме инициализации), JITкомпилятор фактически полностью исключит проверку и саму переменную:
LOOP:
// Console.WriteLine(0)
xor ecx,ecx
call CONSOLE_WRITE_LINE
// while (true)
jmp LOOP
Интересно, что компилятор C # не будет делать эту оптимизациюn:
// int value = 0;
ldc.i4.0
stloc.0
br.s WHILE_CHECK
LOOP_START:
// Console.WriteLine(value)
ldloc.0
call void System.Console::WriteLine(int32)
WHILE_CHECK:
// effectively: if (value >= 0) goto LOOP_START
ldloc.0
ldc.i4.0
bge.s LOOP_START
Опять же, IL и код сборки в моем ответе зависят от платформы и компилятора (даже от CLR).Я не могу предоставить вам подтверждающие документы.Но я уверен, что ни один компилятор не оптимизирует локальную переменную, адрес которой был получен и, более того, использован в качестве аргумента при вызове методов / функций.
Может быть, кто-то из команд Roslyn и RyuJIT мог бы дать вамлучший ответ.