В CLR каждая функция (метод) представляет собой набор IL-команд и вся информация о ней хранится в метаданных модуля. При загрузке модуля для каждого его класса система CLR создает таблицу MethodTable, содержащую информацию о методах класса. Каждый метод класса описывается структурой MethodDesc, одно из полей которой содержит адрес скомпилированного метода в памяти (при выполненной JIT-компиляции метода), а другое содержит индекс в таблице MethodTable, по которому указан адрес переходника (thunk), содержимое которого изменяется в процессе выполнения в зависимости от того, скомпилирован метод или нет.
Первоначально (до выполнения JIT-компиляции) в качестве переходника выступает один из четырех т.н. precode переходников CLR: StubPrecode, FixupPrecode, RemotingPrecode или NDirectImportPrecode. Поскольку последний переходник используется только для вызова API-функций Windows, которые можно перехватить и напрямую, то его мы рассматривать не будем.
Основной задачей каждого из precode-переходников является передача адреса структуры MethodDesc,
определяющей используемый метод, внутренней функции ThePreStub (ThePreStubAMD64 для платформы x64, на рисунке отмечена как Stub), которая выполняет следующие задачи:
1.JIT-компиляция метода, идентифицируемого структурой MethodDesc;
2.установка указателя в структуре MethodDesc на сгенерированный native-код;
3.перезапись переходника таким образом, чтобы он осуществлял безусловный переход (jmp) на сгенерированный native-код;
4.выполнение сгенерированного native-кода.
Таким образом, в результате первоначального вызова целевого метода не только сгенерируется и выполнится код метода, но и изменится содержимое переходника, что приведет к прямому вызову сгенерированного native-кода при последующих вызовах метода.
Любой метод .NET, вызываемый из среды CLR, проходит через адрес в таблице MethodTable методов класса. Однако среда CLR предоставляет возможность вызова метода из неуправляемой среды С/С++. Для этого служат следующие функции: GetFunctionPointer класса RuntimeMethodHandle и GetFunctionPointerForDelegate класса Marshal. Адреса, возвращаемые указанными функциями, также являются адресами переходников, среди которых могут быть уже упомянутые StubPrecode, FixupPrecode и RemotingPrecode. В результате первоначального вызова метода происходит его компиляция и выполнение, при последующем вызове – прямой переход на сгенерированный код. При этом важным для нас является то, что для некомпилированного метода при вызове его как через таблицу методов, так и через возвращаемые упомянутыми функциями указатели, происходит вызов внутренней функции ThePreStub.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Sharov, Вы писали:
S>>Нормальной быстрой математики под дотнет нет, большинство реализаций ничего кроме фейспалма не вызывают. Как пример.
S>https://www.centerspace.net/nmath
S>Но там нет того, что нужно ТС.
Здравствуйте, Lexey, Вы писали:
L>Здравствуйте, Sharov, Вы писали:
S>>>Нормальной быстрой математики под дотнет нет, большинство реализаций ничего кроме фейспалма не вызывают. Как пример.
S>>https://www.centerspace.net/nmath
S>>Но там нет того, что нужно ТС.
L>Еще есть: http://numerics.mathdotnet.com/ L>Но, там пока тоже нет длинной арифметики.
Любую длинную арифметику я могу написать сам, и эта задача — интересная и даже простая, по сравнению с задачей оптимизации — заставить программу, просто прочитать RDX регистр,
вместо того чтобы городить 4 умножения (+ обнуления частей + операции сложения), где могло быть одно умножение, и также, потери при операциях с делением.
Будь я разработчиком .NET Framework, не оставил бы без реализации такую очевидную возможность процессора. (деление 128 бит на 64 бит, или умножение 64 бит на 64 бит, и получение 128 бит).
Да, можно перейти на C++ и даже почти целиком, но тогда теряешь остальные вкусные преимущества C#
Я думаю,
ulong * ulong трансформируется в inline-метод, типа,
ulong Multiply (ulong a, ulong b)
а был бы — перегруженный, аналогичный
ulong Multiply (ulong a, ulong b, ref ulong resultHighPart)
Здравствуйте, SergeyY, Вы писали:
SY>Спасибо, интересно. Это они переопределили метод, после копиляции в .NET ?
Да. Только оно совсем не так делается. Для продакшна оно не делается никак. По определению.
Для тестирования и прочих извращений официальный способ здесь, извращенческий тут
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, SergeyY, Вы писали:
SY>>Спасибо, интересно. Это они переопределили метод, после копиляции в .NET ? S>Да. Только оно совсем не так делается. Для продакшна оно не делается никак. По определению.
S>Для тестирования и прочих извращений официальный способ здесь, извращенческий тут
Спасибо, интересно. Ну не такой уж и извращенческий, если 1) в хороших целях делается, и 2) по причине отсутствия лучшей реализации.
Здравствуйте, SergeyY, Вы писали:
SY>Можно ли делать вставки MSIL в код на c# ?
Да, если отхачить компилятор (от МС или из Моно) или написать собственный.
SY>Можно ли подобное сделать, с помощью вставки MSIL в код на C# ? Т.е. заставить после умножения сгенерировать такой машинный код, который прочитает регистр RDX
Вот это сделать невозможно. МСИЛ — это байткод некой виртуальной машины. В этой машине вообще нет понятия "регистр". Все операции осуществляются через стек.
Но можно скомпилировать машинный код и передать ему управление. Естественно, что работать это будет только на совместимом железе. Например, под андройдом или виндофоном это не прокатит.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.