Re[63]: MS забило на дотнет. Питону - да, сишарпу - нет?
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 14.09.21 08:34
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Колега Serginio1 как-то сказал рядом в этом же обсуждении, что ссылка на typeinfo находится по отрицательному смещению VMT (это так в плюсах, и я даже поверил насчёт дотнета, бо давно не всматриваюсь в виртуальные вызовы в дотнете, бо где гоняюсь за эффективностью, там их нет).


Да прошу прощения за недостоверную информацию
https://docs.microsoft.com/en-us/archive/msdn-magazine/2005/may/net-framework-internals-how-the-clr-creates-runtime-objects
Вся правда о TypeHandle в .NET

Ага, значит TypeHandle может быть как указателем на MethodTable, так и указателем на TypeDesc, в зависимости от типа объекта. Для массивов он указывает на TypeDesc. Тип object[][] — это массив, элементами которого являются object[], для которых TypeHandle=TypeDesc. Эта информация объясняет наш пример, но всё ещё остаются некоторые вопросы. Например: а как же отличить, на что именно указывает TypeHandle? Поможет нам в этом дальнейшее изучение исходников CLI:

   FORCEINLINE BOOL IsUnsharedMT() const {
        LEAF_CONTRACT;
        STATIC_CONTRACT_SO_TOLERANT;
        return((m_asTAddr & 2) == 0);
    }

    FORCEINLINE BOOL IsTypeDesc() const  {
        WRAPPER_CONTRACT;
        return(!IsUnsharedMT());
    }

Всё зависит от второго бита в адресе: нулевое значение определяет MethodTable, а единичное — TypeDesc. Если мы работаем с шестнадцатеричными адресами, то можно легко определить вид TypeHandle по последней цифре:

MethodTable: 0, 1, 4, 5, 8, 9, C, D
TypeDesc : 2, 3, 6, 7, A, B, E, F
А теперь взглянем ещё раз на дамп памяти нашего примера. Можно видеть, что для System.Object[] в дампе присутствуют указатели как на его TypeDesc, так и на MethodTable. Не смотря на то, что под TypeHandle в данном случае подразумевается TypeDesc, заголовочный указатель для a[0] всё-таки указывает на MethodTable. Поэтому некорректно говорить о том, что в заголовке каждого объекта хранится TypeHandle: там хранится указатель на MethodTable, а это далеко не всегда одно и то же.


Пример 4
Последний пример проиллюстрирует недавно полученное правило про последнюю цифру адреса. Мы можем получить TypeHandle прямо из управляемого кода, а по этому значению мы можем определить, что именно под ним подразумевается:


private void Run()
{
    Print(typeof(int));
    Print(typeof(object));
    Print(typeof(Stream));
    Print(typeof(int[]));
    Print(typeof(int[][]));
    Print(typeof(object[]));
}


private void Print(Type type)
{
    bool isTypeDesc = ((int)type.TypeHandle.Value & 2) > 0;
    Console.WriteLine("{0}: {1} => {2}", 
        type.Name.PadRight(10), 
        type.TypeHandle.Value.ToString("X"), 
        (isTypeDesc ? "TypeDesc" : "MethodTable"));
}

У меня этот код выводит следующее:

Int32 : 65C4C480 => MethodTable
Object : 65C4B060 => MethodTable
Stream : 65C4D954 => MethodTable
Int32[] : 65854C8A => TypeDesc
Int32[][] : 658F6BD6 => TypeDesc
Object[] : 65854D7A => TypeDesc
Выводы
В ходе нашего маленького исследования были получены следующие выводы:

TypeHandle является указателем либо на MethodTable, либо на TypeDesc (зависит от типа объекта)
В заголовке каждого объекта для идентификации его типа всегда хранится указатель на MethodTable (это не всегда TypeHandle)
Для массивов, чьи элементы должны представлять ссылочный тип, хранится дополнительное поле, которое представляет собой TypeHandle для типа элементов.

и солнце б утром не вставало, когда бы не было меня
Отредактировано 14.09.2021 9:22 Serginio1 . Предыдущая версия . Еще …
Отредактировано 14.09.2021 9:20 Serginio1 . Предыдущая версия .
Отредактировано 14.09.2021 9:13 Serginio1 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.