Вы не внимательно прочитали мой комментарий. Если вы записываете гуид и читаете в потоках, то максимум что вам грозит - это прочтение гуида где только часть записалась, а остальное - нули/мусор. Возможно это приведет к ошибкам в логике программы - но это уже на совести программиста. Несинхранизированная запись юниона, в котором вы делаете Unsafe.As над shared слотом в зависимости от тэга может привести к крашу рантайма. Фактически, это UB для джита/рантайма.
Нет. Присвоение структурного поля никогда не приведет к крашу рантайма, там не будет атомарности как это и обещает модель памяти, но никаких крашей рантайма не будет. А здесь без синхронизации может возникнуть ситуация когда вызывается инстанс метод (или например поле) у объекта, которые еще не успел переключится в новый объект (или наоборот - объект уже новый, а тэг старый).
Никаким образом это не решает проблему. Представьте что у вас поле класса - юнион Pet pet. вы меняете значение этого поля с Cat на Dog. в каком порядке вы должны менять тэг и shared слот чтобы читающий это поле другой поток всё это увидел без потенциального краша рантайма?
Проблема ExplicitUnion в атомарности - вы должны и значение и тэг поменять атомарно, иначе это тайп-сефити баг потенциальный. А учитывая что больше чем 64 бита атомарно не поменять…
Думаю не надо объяснять что object и не-обджект в одном слоте вообще даже теоретически нельзя хранить в .NET
Имею право полагать, что до выхода Native AOT, возможности -p:PublishReadyToRun=true не было
Нет, не имеете. R2R был с самых первых версий .NET Core, до этого с нулевых (по-моему с .NET 2.0 или даже 1.1) был NGen - +/- тоже самое (чуть с другой философией, fragile). Какое-то время .NET Core даже поддерживал оба режиме - NGen и R2R.
В C# любая рекурсия (т.е. вызов функцией самой себя) требует O(n) памяти только для стека
Это не так, JIT компилятор где сможет, прекрасно расставляет тейл коллы сам (а в очень редких ситуациях может даже развернуть в цикл). tail. prefix который использует F# это больше как обязательное требование к рантайму, в духе "мне все равно как, сделай тут tail call, в случае если быстрый (имплицитный) тейл-колл нельзя вставить, джиту придется вставлять специальный хелпер колл от чего будет удар по перфу.
Я не думаю что есть хоть какие шансы на появление этого в синтаксисе C#, хз зачем вы его тут перечислили.
InlineArray даст защиту от выхода за границы (через исключение). в вашем случае это полный ансейф, сугубо на ваших плечах отвественность что вы правильно посчитали длины и оффсеты у Array
std::array<int, 10> -- это и есть const generics, под них надо изменять метадату, может когда и сделают, но для этого нужна везкая причина (в идеале, еще фичи которым нужны изменения)
var handlePtr = (IntPtr)Unsafe.AsPointer(ref handle);
Сразу видно, не читали статью ;-) вы тут делаете предположение что handle всегда на стеке или в нативной памяти, хотя ничего не помешает ему быть, например, полем класса или статическим полем и привет GC corruption баг (если это не ref struct конечно).
Т.е. вы используете неявный контракт вызова вашего метода, который никому не известен
POH не очень удачная фича по итогу получилась, лучше бы ее вообще не делали. Публичные апи к ней привели к тому что смесь долго- и коротко- живущий пиннед массивов приводят в дикой фрагментизации кучи которую нельзя дефрагментировать.
Я лично не сильно фанат заметания unsafe под ковер. если у вас интероп слой, то и используйте в нем uv_getaddrinfo_t* и маршаллить ничего не надо, сразу в сигнатуре параметра объявить
из примера выше:
где тут нет объектов?
Вы не внимательно прочитали мой комментарий. Если вы записываете гуид и читаете в потоках, то максимум что вам грозит - это прочтение гуида где только часть записалась, а остальное - нули/мусор. Возможно это приведет к ошибкам в логике программы - но это уже на совести программиста. Несинхранизированная запись юниона, в котором вы делаете Unsafe.As над shared слотом в зависимости от тэга может привести к крашу рантайма. Фактически, это UB для джита/рантайма.
Нет. Присвоение структурного поля никогда не приведет к крашу рантайма, там не будет атомарности как это и обещает модель памяти, но никаких крашей рантайма не будет. А здесь без синхронизации может возникнуть ситуация когда вызывается инстанс метод (или например поле) у объекта, которые еще не успел переключится в новый объект (или наоборот - объект уже новый, а тэг старый).
Никаким образом это не решает проблему. Представьте что у вас поле класса - юнион Pet pet. вы меняете значение этого поля с Cat на Dog. в каком порядке вы должны менять тэг и shared слот чтобы читающий это поле другой поток всё это увидел без потенциального краша рантайма?
Проблема ExplicitUnion в атомарности - вы должны и значение и тэг поменять атомарно, иначе это тайп-сефити баг потенциальный. А учитывая что больше чем 64 бита атомарно не поменять…
Думаю не надо объяснять что object и не-обджект в одном слоте вообще даже теоретически нельзя хранить в .NET
Нет, не имеете. R2R был с самых первых версий .NET Core, до этого с нулевых (по-моему с .NET 2.0 или даже 1.1) был NGen - +/- тоже самое (чуть с другой философией, fragile). Какое-то время .NET Core даже поддерживал оба режиме - NGen и R2R.
"Появилось понятие R2R"
очень странная статья, понятно что это ИИ, но как-будто какой-то устаревший, из 2023 - смесь бесполезных фактов + откровенно неверных утверждений, аля
или
наверное неверных утверждений еще больше, я вскольз глянул
Там скорее про то что большое кол-во public API начнут требовать unsafe{} контекст, т.к. они не безопасны. Остальное вокруг этого.
вот вам 2 примера https://godbolt.org/z/9ne5K5G16
Какую именно это меняет семантику и результат программы? наличие или нет StackOverflowException? это не семантика
Это не так, JIT компилятор где сможет, прекрасно расставляет тейл коллы сам (а в очень редких ситуациях может даже развернуть в цикл). tail. prefix который использует F# это больше как обязательное требование к рантайму, в духе "мне все равно как, сделай тут tail call, в случае если быстрый (имплицитный) тейл-колл нельзя вставить, джиту придется вставлять специальный хелпер колл от чего будет удар по перфу.
Я не думаю что есть хоть какие шансы на появление этого в синтаксисе C#, хз зачем вы его тут перечислили.
stackalloc или нет, это всё еще никак не связано с кэшем процессора или оперативной памятью, ортогональные вещи.
InlineArray даст защиту от выхода за границы (через исключение). в вашем случае это полный ансейф, сугубо на ваших плечах отвественность что вы правильно посчитали длины и оффсеты у Array
std::array<int, 10> -- это и есть const generics, под них надо изменять метадату, может когда и сделают, но для этого нужна везкая причина (в идеале, еще фичи которым нужны изменения)
Сразу видно, не читали статью ;-) вы тут делаете предположение что handle всегда на стеке или в нативной памяти, хотя ничего не помешает ему быть, например, полем класса или статическим полем и привет GC corruption баг (если это не ref struct конечно).
Т.е. вы используете неявный контракт вызова вашего метода, который никому не известен
Что конкретно непонятно? В целом, можно было реализовать через const generics, но неизвестно будут ли они когда-либо из-за сложности
POH не очень удачная фича по итогу получилась, лучше бы ее вообще не делали. Публичные апи к ней привели к тому что смесь долго- и коротко- живущий пиннед массивов приводят в дикой фрагментизации кучи которую нельзя дефрагментировать.
они являются unsafe потому что ничего вам не мешает ошибится с размером и это не вызовет никаких рантайм проверок. Вот пример:
такой код даже отработает (и станет кандидатом в CVE)
Я лично не сильно фанат заметания unsafe под ковер. если у вас интероп слой, то и используйте в нем
uv_getaddrinfo_t*и маршаллить ничего не надо, сразу в сигнатуре параметра объявить