æ¬å šäœãGitHubïŒ CLR Bookã§å©çšå¯èœã«ãªããŸãã ã ããåé¡ãšãã«ãªã¯ãšã¹ãã¯å€§æè¿ã§ã:)
ããã¯ã åã®æ§é ãšãã®VMTã«é¢ããç« ããã®æç²ã§ãã
ã¡ã¢ãªå ã®ãªããžã§ã¯ãã®æ§é
ãããŸã§ã®ãšããã éèŠãªã¿ã€ããšåç §ã¿ã€ãã®éãã«ã€ããŠèšãã° ãæçµéçºè ã®èŠ³ç¹ãããã®ãããã¯ã«åãçµãã§ããŸããã ããªãã¡ CLRã¬ãã«ã§å®éã«ã©ã®ããã«é 眮ãããŠããã®ããããããã®å éšã§ç¹å®ã®ã¡ã«ããºã ãã©ã®ããã«äœãããŠããã®ãã«ã€ããŠã¯èŠãŠããŸããã å®éã«æçµçµæãèŠãŸããã ãã ããç©äºã®æ¬è³ªãããæ·±ãç解ããCLRå ã§çºçããéæ³ã«é¢ããæåŸã«æ®ã£ãèããæšãŠãã«ã¯ããã®å èã調ã¹ã䟡å€ããããŸãã
ã泚æ
Habréã§å ¬éãããŠããç« ã¯æŽæ°ãããŠãããããããããã§ã«å€ããã®ã§ãã ãã®ãããææ°ã®ããã¹ãã«ã€ããŠã¯å ã«æ»ããŠãã ããã
- CLR BookïŒ GitHubãç®æ¬¡
- CLR BookïŒ GitHubãç«
- ãªãªãŒã¹0.5.2ã®æžç±ãPDFïŒ GitHubãªãªãŒã¹
åã€ã³ã¹ã¿ã³ã¹ã®å éšæ§é
ã¯ã©ã¹ãããŒã¿åãšããŠè©±ãå Žåããã®ããŒã¿åã«ã€ããŠã®äŒè©±ã§ãåºæ¬çãªããã€ã¹ãæãåºãã ãã§ååã§ãã
object
åããå§ããŸããããããã¯åºæ¬åã§ããããã¹ãŠã®åç §åã®æ§é ã圢æããŸãã
System.object
---------------------------------------------- | SyncBlkIndx | VMTPtr | Data | ---------------------------------------------- | 4 / 8 | 4 / 8 | 4 / 8 | ---------------------------------------------- | 0xFFF..FFF | 0xXXX..XXX | 0 | ---------------------------------------------- ^ | . .. , VMT Sum size = 12 (x86) .. 24 (x64)
ããªãã¡ å®éããµã€ãºã¯ã¢ããªã±ãŒã·ã§ã³ãå®è¡ãããæçµçãªãã©ãããã©ãŒã ã«äŸåããŸãã
ä»ãç§ãã¡ãäœãæ±ã£ãŠããããããã«ç解ããããã«ã
VMTPtr
ãã€ã³ã¿ãŒãè¿œã£ãŠã¿ãŸãããã åã·ã¹ãã å šäœã«ãšã£ãŠããã®ãã€ã³ã¿ãŒã¯æãéèŠã§ããç¶æ¿ãã€ã³ã¿ãŒãã§ãŒã¹ã®å®è£ ãåå€æãæ©èœããã®ã¯ããããä»ããããšã§ãã ãã®ãã€ã³ã¿ãŒã¯ã.NET CLRåã·ã¹ãã ãžã®åç §ã§ãã
ä»®æ³ã¡ãœããè¡š
ããŒãã«èªäœã®èª¬æã¯GitHub CoreCLRã®ã¢ãã¬ã¹ã§å ¥æã§ããŸããäœåãªãã®ããã¹ãŠç Žæ£ãããšïŒãããŠ4381è¡ãããŸãïŒCoreCLRããŒã ã®ã¡ã³ããŒã¯æ¥ãããããå±ã§ã¯ãããŸããïŒã 次ã®ããã«ãªããŸã ã
ããã¯CoreCLRã®ããŒãžã§ã³ã§ãã .NET Frameworkã®ãã£ãŒã«ãæ§é ãèŠããšããã£ãŒã«ãã®é 眮ãç°ãªããŸãã
// Low WORD is component size for array and string types (HasComponentSize() returns true). // Used for flags otherwise. DWORD m_dwFlags; // Base size of instance of this class when allocated on the heap DWORD m_BaseSize; WORD m_wFlags2; // Class token if it fits into 16-bits. If this is (WORD)-1, the class token is stored in the TokenOverflow optional member. WORD m_wToken; // <NICE> In the normal cases we shouldn't need a full word for each of these </NICE> WORD m_wNumVirtuals; WORD m_wNumInterfaces;
åæããŠãæãããèŠããŸãã æãããããšã¯ããã£ãŒã«ãã6ã€ãããªããšããããšã§ã¯ãããŸããïŒä»ã®ãã£ãŒã«ãã¯ã©ãã«ãããŸããïŒïŒããããããããã«å°éããããã«ã4,100è¡ã®ããžãã¯ãã¹ãããããå¿ èŠããããŸããã ããããå¿ã倱ããããã«å©çãåŸãããšããªãã§ãã ããïŒä»ã®ãšãããä»ã®ãã£ãŒã«ããäœãæå³ããã®ãããããŸãããã `m_BaseSize`ãã£ãŒã«ãã¯é åçã«èŠããŸãã ã³ã¡ã³ããããããããã«ãããã¯åã€ã³ã¹ã¿ã³ã¹ã®å®éã®ãµã€ãºã§ãã æŠãã«è¡ãããïŒ
VMTã¢ãã¬ã¹ãååŸããã«ã¯ã次ã®2ã€ã®æ¹æ³ããããŸããå°é£ãªãšãããããªããžã§ã¯ãã¢ãã¬ã¹ãååŸããããVMTã§ãïŒãã®ã³ãŒãã®äžéšã¯æ¢ã«ãã®æ¬ã®ããŒãžã«ãããŸããããscããªãã§ãã ããïŒæ¢ããããªãã§ãïŒã
class Program { public static unsafe void Main() { Union x = new Union(); x.Reference.Value = "Hello!"; // , // VMT // - (IntPtr*)x.Value.Value - ( ) // - *(IntPtr*)x.Value.Value - VMT // - (void *)*(IntPtr*)x.Value.Value - void *vmt = (void *)*(IntPtr*)x.Value.Value; // VMT; Console.WriteLine((ulong)vmt); } [StructLayout(LayoutKind.Explicit)] public class Union { public Union() { Value = new Holder<IntPtr>(); Reference = new Holder<object>(); } [FieldOffset(0)] public Holder<IntPtr> Value; [FieldOffset(0)] public Holder<object> Reference; } public class Holder<T> { public T Value; } }
ãŸãã¯ã.NET FCL APIã«ãã£ãŠãããšãŸã£ããåãã¢ãã¬ã¹ãè¿ãããŸãã
var vmt = typeof(string).TypeHandle.Value;
2çªç®ã®æ¹æ³ã¯ããã¡ããç°¡åã§ãïŒãã ããããé·ãæ©èœããŸãïŒã ãã ããåè ã®ç¥èã¯ãåã®ã€ã³ã¹ã¿ã³ã¹ã®æ§é ãç解ããäžã§éåžžã«éèŠã§ãã ãã ãã2çªç®ã®æ¹æ³ã䜿çšãããšãèªä¿¡ãå¢ããŸããAPIã¡ãœãããåŒã³åºããšãVMTã䜿çšããææžåãããæ¹æ³ã䜿çšãããããªãã®ã«ãªããŸãã ãããŠããã€ã³ã¿ãŒãééããå Žåããããã ãããã `VMT *`ãä¿åããããšã¯ãã»ãšãã©ãã¹ãŠã®OOPèšèªãš.NETãã©ãããã©ãŒã å šäœã«ãšã£ãŠæšæºã§ããããšãå¿ããªãã§ãã ãããåžžã«åãå Žæã«ãããŸãã
ã€ã³ã¹ã¿ã³ã¹ã®ãµã€ãºã®èŠ³ç¹ããåæ§é ã®åé¡ã調ã¹ãŠã¿ãŸãããã ç§ãã¡ã¯ããããæœè±¡çã«ç 究ããå¿ èŠãããã ãã§ãªãïŒããã¯åã«éå±ã§ãïŒãããã«ãéåžžã®æ¹æ³ã§ã¯æœåºã§ããªããã®ãããªå©ç¹ãåŒãåºãããšãè©Šã¿ãŸãã
åç §åã§ã¯ãªããå€åã®sizeofããªãã§ããïŒ å®éã«è³ªåã¯éããŠããŸã 誰ãåç §åã®ãµã€ãºãèšç®ããããšãæ°ã«ããŸããã ã€ãŸããå¯äžã®ããšã¯ã2ã€ã®åç §åã®åºå®ãããŠããªããµã€ãºïŒ `Array`ãš` String`ã§ãã ç¹å®ã®ãªãã·ã§ã³ã«å®å šã«äŸåãããGenericãã°ã«ãŒããšåæ§ã«ã ããªãã¡ `sizeofïŒ..ïŒ`æŒç®åã§ã¯ã§ããŸããã§ããïŒç¹å®ã®ã€ã³ã¹ã¿ã³ã¹ãæäœããå¿ èŠããããŸãã ãããã `static int System.Object.SizeOfïŒobject objïŒ`ã®ãããªã¡ãœãããäœæããããšã誰ãæ°ã«ããŸããã ã§ã¯ããªããã€ã¯ããœããã¯ãã®æ¹æ³ãå®è£ ããªãã£ãã®ã§ããïŒ åœŒããç解ããŠãã.NETãã©ãããã©ãŒã ã¯ãéçºè ãç¹å®ã®ãã€ããéåžžã«å¿é ãããã©ãããã©ãŒã ã§ã¯ãªããšããèãããããŸãã ãã®å Žåãã¹ããªããããã¶ãŒããŒãã«ç°¡åã«é éã§ããŸãã ããã«ãç§ãã¡ãå®è£ ããã»ãšãã©ã®ã¿ã€ãã®ããŒã¿ã¯ããã®ãããªå€§éãå æããŸããã ãã ããå¿ èŠãªãã®ããã¹ãŠå¿ èŠãªå Žåã¯ãå¿ èŠã«å¿ããŠãã¹ãŠã®ãµã€ãºãèšç®ããŸãã ãã¡ããåŸè ã¯è°è«ã®äœå°ããããŸãã
ããããæ°ãæ£ãããªãããã«ããŸãããã ãããã£ãŠãã€ã³ã¹ã¿ã³ã¹ã®ãµã€ãºãåºå®ãããŠããã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã®ãµã€ãºãååŸããã«ã¯ã次ã®ã³ãŒããèšè¿°ããã ãã§ååã§ãã
unsafe int SizeOf(Type type) { MethodTable *pvmt = (MethodTable *)type.TypeHandle.Value.ToPointer(); return pvmt->Size; } [StructLayout(LayoutKind.Explicit)] public struct MethodTable { [FieldOffset(4)] public int Size; } class Sample { int x; } class GenericSample<T> { T fld; } // ... Console.WriteLine(SizeOf(typeof(Sample)));
ããã§ãç§ãã¡ã¯ä»äœãããŸãããïŒ æåã®ã¹ãããã¯ãä»®æ³ã¡ãœããã®ããŒãã«ãžã®ãã€ã³ã¿ãŒãååŸããããšã§ãã 次ã«ãã¿ã€ããä»®æ³ã¡ãœããã®ããŒãã«ïŒéåžžã«åçŽåãããããŒãžã§ã³ïŒãžã®ãã€ã³ã¿ãŒã«å°ããŸããã ãã®åŸããµã€ãºãèªã¿åã£ãŠ `12`ãååŸããŸããããã¯ã32ããããã©ãããã©ãŒã ã®` SyncBlockIndex + VMT_Ptr + field x`ãã£ãŒã«ãã®ãµã€ãºã®åèšã§ãã ããŸããŸãªã¿ã€ããè©ŠããŠã¿ããšã次ã®è¡šãåŸãããŸãã
ã¿ã€ããŸãã¯ãã®å®çŸ© | 倧ãã | 解説 |
察象 | 12 | SyncBlk + VMT +空ã®ãã£ãŒã«ã
|
Int16 | 12 | Boxed Int16ïŒSyncBlk + VMT +ããŒã¿
ïŒx86ã§ã¯4ãã€ãã§æŽåïŒ |
Int32 | 12 | Boxed Int32ïŒSyncBlk + VMT +ããŒã¿
|
Int64 | 16 | Boxed Int64ïŒSyncBlk + VMT +ããŒã¿
|
ãã£ãŒ | 12 | å²ã¿æåïŒSyncBlk + VMT +ããŒã¿
ïŒx86ã§ã¯4ãã€ãã§æŽåïŒ |
ããã« | 16 | Boxed DoubleïŒSyncBlk + VMT +ããŒã¿
|
IEnumerable | 0 | ã€ã³ã¿ãŒãã§ã€ã¹ã«ã¯ãµã€ãºããããŸããïŒobj.GetTypeïŒïŒãåãå¿
èŠããããŸã
|
ãªã¹ã[T] | 24 | ãªã¹ã[T]å
ã®ã¢ã€ãã ã®æ°ã¯é¢ä¿ãããŸãã
åãã ãã èæ ®ãããŠããªãé åã«ããŒã¿ãä¿åããŸã |
GenericSample [int] | 12 | ã芧ã®ãšããããžã§ããªãã¯ã¯çŽ æŽãããã§ãã ãµã€ãºã¯å€æŽãããŠããŸãã
ãªããªã ããŒã¿ã¯ãboxed intãšåãå Žæã«ãããŸãã çµæïŒSyncBlk + VMT + data = 12ãã€ãïŒx86ïŒ |
GenericSample [Int64] | 16 | åæ§ã«
|
GenericSample [IEnumerable] | 12 | åæ§ã«
|
GenericSample [DateTime] | 16 | åæ§ã«
|
ã²ã | 14 | ãã®å€ã¯ããã¹ãŠã®è¡ã«å¯ŸããŠè¿ãããŸãã
ãªããªã å®éã®ãµã€ãºã¯åçã«èæ ®ããå¿ èŠããããŸãã ãã ãã空ã®æååã®ãµã€ãºã«ã¯é©ããŠããŸãã ãµã€ãºã調æŽãããŠããªãããšã«æ³šæããŠãã ãã ããã深床ïŒåºæ¬çã«ãã®ãã£ãŒã«ãã䜿çšãããŸã ããŠã¯ãããªã |
int [] {1} | 24554 | ãã®å Žæã«ããé
åã®å Žå
å®å šã«ç°ãªãããŒã¿ãšãã®ãµã€ãºã¯ç°ãªããŸã èæ ®ãããå¿ èŠããããããä¿®æ£ å¥ã« |
ã芧ã®ãšãããã·ã¹ãã ãåã®ã€ã³ã¹ã¿ã³ã¹ã®ãµã€ãºã§ããŒã¿ãä¿åãããšããå®éã«ã¯åç §åã®ããŒã¿ïŒåç §ããªã¢ã³ãã®éèŠãªãã®ãå«ãïŒãä¿åãããŸãã ããã€ãã®çµè«ãå°ããŸãããã
- éèŠãªåãå€ãšããŠã©ãã ãåãããç¥ãããå Žåã¯ã `sizeofïŒTTypeïŒ`ã䜿çšããŸã
- ãã¯ã·ã³ã°ã«ãããââã³ã¹ããèšç®ããå Žåã¯ããsizeofïŒTTypeïŒããããã»ããµã®ã¯ãŒããµã€ãºïŒ4ãŸãã¯8ãã€ãïŒã«åãäžããããã«2ã¯ãŒãè¿œå ã§ããŸãã ãŸãã¯ããã®å€ããVMTãã¿ã€ãããååŸããŸãã
- å¿ èŠã«å¿ããŠãããŒãã«ã¡ã¢ãªãå²ãåœãŠãã®ã«ãããã³ã¹ããç解ããããã«ã3ã€ã®ãªãã·ã§ã³ããããŸãã
System.string
å®çšçãªåé¡ã®è¡ã«ã€ããŠã¯å¥ã«èª¬æããŸãããã®æ¯èŒçå°ããªã¯ã©ã¹ã«ç« å šäœãå²ãåœãŠãããšãã§ããŸãã ãŸããVMTã®æ§ç¯ã«é¢ããç« ã§ã¯ãäœã¬ãã«ã§ã®ã©ã€ã³ã®æ§ç¯ã«ã€ããŠèª¬æããŸãã UTF16æšæºã¯ãæååãæ ŒçŽããããã«äœ¿çšãããŸãã ã€ãŸããåæåã«ã¯2ãã€ããå¿ èŠã§ãã ããã«ãåè¡ã®æåŸã«ãã«ã¿ãŒãããŒã¿ãæ ŒçŽãããŸãïŒã€ãŸããè¡ãçµäºããããšãèå¥ããå€ïŒã æååã®é·ãã¯ãInt32çªå·ãšããŠãä¿åãããŸã-å¿ èŠã«ãªããã³ã«é·ããã«ãŠã³ãããªãããã«ããããã§ãã ãšã³ã³ãŒãã£ã³ã°ã«ã€ããŠã¯å¥ã«èª¬æããŸãããä»ã®ãšããã¯ãã®æ å ±ã§ååã§ãã
// .NET Framework 4 ------------------------------------------------------------------------- | SyncBlkIndx | VMTPtr | Length | char | char | Term | ------------------------------------------------------------------------- | 4 / 8 | 4 / 8 | 4 | 2 . | 2 . | 2 . | ------------------------------------------------------------------------- | -1 | 0xXXXXXXXX | 2 | a | b | nil | ------------------------------------------------------------------------- Term - null terminator Sum size = (12 (24) + 2 + (Len*2)) -> . (20 ) // .NET Framework 3.5 ------------------------------------------------------------------------------ | SyncBlkIndx| VMTPtr | ArrayLength | Length | char | char | Term | ------------------------------------------------------------------------------ | 4 / 8 | 4 / 8 | 4 | 4 | 2 . | 2 . | 2 . | ------------------------------------------------------------------------------ | -1 | 0xXXXXXXXX | 3 | 2 | a | b | nil | ------------------------------------------------------------------------------ Term - null terminator Sum size = (16 (32) + 2 + (Len*2)) -> . (24 )
æååã®ãµã€ãºãæ°ããæ¹æ³ãæããããã«ã¡ãœãããæžãçŽããŸãïŒ
unsafe int SizeOf(object obj) { var majorNetVersion = Environment.Version.Major; var type = obj.GetType(); var href = Union.GetRef(obj).ToInt64(); var DWORD = sizeof(IntPtr); var baseSize = 3 * DWORD; if (type == typeof(string)) { if (majorNetVersion >= 4) { var length = (int)*(int*)(href + DWORD /* skip vmt */); return DWORD * ((baseSize + 2 + 2 * length + (DWORD-1)) / DWORD); } else { // on 1.0 -> 3.5 string have additional RealLength field var arrlength = *(int*)(href + DWORD /* skip vmt */); var length = *(int*)(href + DWORD /* skip vmt */ + 4 /* skip length */); return DWORD * ((baseSize + 2 + 2 * length + (DWORD -1)) / DWORD); } } else if (type.BaseType == typeof(Array) || type == typeof(Array)) { return ((ArrayInfo*)href)->SizeOf(); } return SizeOf(type); }
`SizeOfïŒtypeïŒ`ã¯å€ãå®è£ ãåŒã³åºããŸã-åºå®é·ã®åç §åã®å Žåã
å®éã«ã³ãŒãã確èªããŸãããïŒ
Action<string> stringWriter = (arg) => { Console.WriteLine($"Length of `{arg}` string: {SizeOf(arg)}"); }; stringWriter("a"); stringWriter("ab"); stringWriter("abc"); stringWriter("abcd"); stringWriter("abcde"); stringWriter("abcdef"); } ----- Length of `a` string: 16 Length of `ab` string: 20 Length of `abc` string: 20 Length of `abcd` string: 24 Length of `abcde` string: 24 Length of `abcdef` string: 28
èšç®ã§ã¯ãè¡ãµã€ãºã¯ç·åœ¢ã§ã¯ãªã段éçã«ãã€ãŸã2æåããšã«å¢å ããŸãã ããã¯ãåæåã®ãµã€ãºã2ãã€ãã§ãããäºãã«ç¶ãããã§ãã ãã ããæçµãµã€ãºã¯ããã¬ãŒã¹ãªãã§ããã»ããµã®å®¹éã§å²ãå¿ èŠããããŸãã ããªãã¡ äžéšã®è¡ã¯ãããã«2ãã€ããã¢ãããããŸãã ç§ãã¡ã®ä»äºã®çµæã¯çŽ æŽãããã§ãããã®è¡ãã©ããããã®è²»çšããããããèšç®ã§ããŸãã æåŸã®ã¹ãããã¯ãã¡ã¢ãªå ã®é åã®ãµã€ãºãèšç®ããã¿ã¹ã¯ãããã«å®çšçã«ããæ¹æ³ãèŠã€ããããšã§ãã次ã®è³ªåã«çããã¡ãœãããäœæããŸããããSOHã«é©åããããã«ã¯ãã©ã®ãµã€ãºã®é åãåãå¿ èŠããããã Lengthããããã£ã䜿çšãããšãããåççã§é«éã«ãªãããã«æãããããããŸããããå®éã«ã¯ãåäœãé ããªããŸãïŒè¿œå ã³ã¹ãã
é å
é åã®æ§é ã¯ããè€éã§ãïŒé åã¯æ§é ã®ããªã¢ã³ããæã€ããšãã§ããŸãïŒ
- æå³ã®ããåãä¿åããããšããåç §ãä¿åããããšãã§ããŸã
- é åã«ã¯1ã€ãŸãã¯è€æ°ã®æ¬¡å ãå«ããããšãã§ããŸã
- å枬å®ã¯ãã0ããŸãã¯ä»ã®æ°åã§éå§ã§ããŸãïŒããã¯ãç§ã®æèŠã§ã¯éåžžã«è°è«ã®äœå°ã®ããæ©äŒã§ãã
ãããã£ãŠãé åã®å®è£ ã«ã¯å€å°ã®æ··ä¹±ããããæçµçãªé åã®ãµã€ãºãæ£ç¢ºã«äºæž¬ããããšãã§ããŸãããèŠçŽ ã®æ°ã«ãµã€ãºãæããã ãã§ã¯äžååã§ãã ãã¡ãããã»ãšãã©ã®å Žåãããã§ã»ãŒååã§ãã LOHã«å ¥ãã®ãæããšãããµã€ãºã¯éèŠã«ãªããŸãã ãã ããããã«ã¯ãªãã·ã§ã³ããããŸãã85000ã§å¢çãè¶ãããã©ãããç解ããããã«ããèã®äžãã§èšç®ããããµã€ãºã«äžèšã®å®æ°ïŒ100ãªã©ïŒãåçŽã«ã¹ããŒã§ããŸãã ãã ãããã®ã»ã¯ã·ã§ã³ã®ãã¬ãŒã ã¯ãŒã¯å ã§ã¯ãã¿ã¹ã¯ã¯å€å°ç°ãªããŸããåã®æ§é ãç解ããããšã§ãã ãããŠãããèŠãŠãã ããïŒ
// -------------------------------------------------------------------------------- | SBI | VMTPtr |Total | Len_1 | Len_2 | .. | Len_N | Term | VMT_Child | --------------------------opt-------opt------------opt-------opt--------opt----- | 4 / 8 | 4 / 8 | 4 | 4 | 4 | | 4 | 4 | 4/8 | -------------------------------------------------------------------------------- |0xFF.FF|0xXX.XX | ? | ? | ? | | ? |0x00.00| 0xXX..XX | -------------------------------------------------------------------------------- - opt: - SBI: Sync Block Index - VMT_Child: - Total: . - Len_2..Len_N + Term: 1 ( VMT->Flags)
ã芧ã®ãšãããã¿ã€ãããããŒã«ã¯é åã®æ¬¡å ã«é¢ããããŒã¿ãæ ŒçŽãããŸãããã®æ°ã¯1ãŸãã¯éåžžã«å€§ããå¯èœæ§ããããŸããå®éããµã€ãºã¯nullã¿ãŒãããŒã¿ãŒã«ãã£ãŠã®ã¿å¶éãããŸããã€ãŸããåæãå®äºããŸãã ãã®äŸã¯[GettingInstanceSize]ãã¡ã€ã«ïŒ./ samples / GettingInstanceSize.linqïŒã§å®å šã«å©çšã§ããŸãã以äžã§ã¯ãæãéèŠãªéšåã®ã¿ã瀺ããŸãã
public int SizeOf() { var total = 0; int elementsize; fixed (void* entity = &MethodTable) { var arr = Union.GetObj<Array>((IntPtr)entity); var elementType = arr.GetType().GetElementType(); if (elementType.IsValueType) { var typecode = Type.GetTypeCode(elementType); switch (typecode) { case TypeCode.Byte: case TypeCode.SByte: case TypeCode.Boolean: elementsize = 1; break; case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Char: elementsize = 2; break; case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Single: elementsize = 4; break; case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Double: elementsize = 8; break; case TypeCode.Decimal: elementsize = 12; break; default: var info = (MethodTable*)elementType.TypeHandle.Value; elementsize = info->Size - 2 * sizeof(IntPtr); // sync blk + vmt ptr break; } } else { elementsize = IntPtr.Size; } // Header total += 3 * sizeof(IntPtr); // sync blk + vmt ptr + total length total += elementType.IsValueType ? 0 : sizeof(IntPtr); // MethodsTable for refTypes total += IsMultidimentional ? Dimensions * sizeof(int) : 0; } // Contents total += (int)TotalLength * elementsize; // align size to IntPtr if ((total % sizeof(IntPtr)) != 0) { total += sizeof(IntPtr) - total % (sizeof(IntPtr)); } return total; }
ãã®ã³ãŒãã¯ãé åã¿ã€ãã®ãã¹ãŠã®ããªãšãŒã·ã§ã³ãèæ ®ãããã®ãµã€ãºãèšç®ããããã«äœ¿çšã§ããŸãã
Console.WriteLine($"size of int[]{{1,2}}: {SizeOf(new int[2])}"); Console.WriteLine($"size of int[2,1]{{1,2}}: {SizeOf(new int[1,2])}"); Console.WriteLine($"size of int[2,3,4,5]{{...}}: {SizeOf(new int[2, 3, 4, 5])}"); --- size of int[]{1,2}: 20 size of int[2,1]{1,2}: 32 size of int[2,3,4,5]{...}: 512
ã»ã¯ã·ã§ã³ã®çµè«
ãã®æ®µéã§ãããªãéèŠãªããšãããã€ãåŠã³ãŸããã æåã«ãåç §åãåºå®åã®åç §åããžã§ããªãã¯åãããã³å¯å€ãµã€ãºã®åç §åã®3ã€ã®ã°ã«ãŒãã«åããŸããã ãŸããããããã¿ã€ãã®æçµã€ã³ã¹ã¿ã³ã¹ã®æ§é ãç解ããããšãåŠã³ãŸããïŒåœé¢ãVMTã®æ§é ã«ã€ããŠã¯èšåããŸããããããŸã§ã®ãšããã1ã€ã®ãã£ãŒã«ãã®ã¿ãå®å šã«ç解ããŸããããããçŽ æŽãããææã§ãïŒã åºå®ãµã€ãºã®åç §åïŒãã¹ãŠãéåžžã«åçŽïŒãŸãã¯äžå®ãµã€ãºã®åç §åïŒé åãŸãã¯æååã ãµã€ãºãäœææã«æ±ºå®ããããããäžç¢ºãã§ãã å®éããžã§ããªãã¯åã䜿çšãããšããã¹ãŠãåçŽã«ãªããŸããç¹å®ã®ãžã§ããªãã¯åããšã«ãç¬èªã®VMTãäœæãããããã«ç¹å®ã®ãµã€ãºãä»å ãããŸãã
ã¡ãœããè¡š
VMTã¯ã©ã¹
ã¡ãœããããŒãã«ã®èª¬æã¯ã»ãšãã©åŠè¡çãªãã®ã§ããçµå±ã®ãšããããã®ãããªãžã£ã³ã°ã«ã«ç»ããšããããšã¯ãèªåã§å¢ãæããããªãã®ã§ãã äžæ¹ã§ã¯ããã®ãããªãã³ã¯ãšããµã€ãã£ã³ã°ã§èå³æ·±ããã®ãé ããäœãèµ·ãã£ãŠããã®ããããã«æããã«ããããŒã¿ãä¿åããŸãã ãã ããäžæ¹ã§ãMicrosoftã¯ã©ã³ã¿ã€ã ãå€æŽãããããšãã°ãçªç¶ã¡ãœããããŒãã«ã1ã€ã®ãã£ãŒã«ãã«ç§»åããªããšããä¿èšŒãMicrosoftãæäŸããªãããšãç解ããŠããŸãã
ãŸãããã¹ãŠãèŠåããã ä»ã圌ããèŠãŠããã¬ã©ã¹ãéããŠèšãããã«ãäžçã«é£ã³èŸŒã¿ãŸãããã å®éããããŸã§ã¯ãèŠãŠããã¬ã©ã¹å šäœããªããžã§ã¯ãã®æ§é ã®ç¥èã«éå ãããŠããŸããããããŠãçè«çã«ã¯ãå°ãªããšãããããç¥ã£ãŠããã¯ãã§ãã ãããŠæ¬è³ªçã«ããã®ç¥èã¯èŠãŠããã¬ã©ã¹ã®èåŸã«ããã®ã§ã¯ãªããèŠãŠããã¬ã©ã¹ãžã®å ¥ãå£ã§ãã CoreCLRã§èª¬æãããŠãã `MethodTable`æ§é ã«æ»ããŸãããã
// Low WORD is component size for array and string types (HasComponentSize() returns true). // Used for flags otherwise. DWORD m_dwFlags; // Base size of instance of this class when allocated on the heap DWORD m_BaseSize; WORD m_wFlags2; // Class token if it fits into 16-bits. If this is (WORD)-1, the class token is stored in the TokenOverflow optional member. WORD m_wToken; // <NICE> In the normal cases we shouldn't need a full word for each of these </NICE> WORD m_wNumVirtuals; WORD m_wNumInterfaces;
ã€ãŸãããm_wNumVirtualsãããã³ãm_wNumInterfacesããã£ãŒã«ãã«ã ãããã®2ã€ã®ãã£ãŒã«ãã¯ããã¿ã€ãã«å«ãŸããä»®æ³ã¡ãœãããšã€ã³ã¿ãŒãã§ãŒã¹ã®æ°ããšãã質åã«å¯Ÿããçãã決å®ããŸãã ãã®æ§é ã«ã¯ãéåžžã®ã¡ãœããããã£ãŒã«ããããããã£ïŒã¡ãœãããçµåããïŒã«é¢ããæ å ±ã¯ãªãã**ã¯ãªãã¬ã¯ã·ã§ã³**ã«é¢é£ä»ããããŠããŸããã ãã®æ¬è³ªãšç®çã«ããããã®æ§é ã¯ãCLRã§ã®ã¡ãœããåŒã³åºãã®æäœã®ããã«äœæãããŸããïŒå®éããã¹ãŠã®OOPã§ãJavaãC ++ãRubyãªã©ã§ãããã£ãŒã«ãã®å Žæã ããå°ãç°ãªããŸãïŒã ã³ãŒããèŠãŠã¿ãŸãããïŒ
public class Sample { public int _x; public void ChangeTo(int newValue) { _x = newValue; } public virtual GetValue() { return _x; } } public class OverridedSample : Sample { public override GetValue() { return 666; } }
ãããã®ã¯ã©ã¹ãç¡æå³ã«èŠããŠããVMTãèšè¿°ããã®ã«éåžžã«é©ããŠããŸãã ãã®ããã«ãåºæ¬åãšã質åã§ç¶æ¿ããã `ChangeTo`ã¡ãœãããš` GetValue`ã¡ãœããã®éããç解ããå¿ èŠããããŸãã
`ChangeTo`ã¡ãœããã¯äž¡æ¹ã®ã¿ã€ãã«ååšããŸãïŒåå®çŸ©ã§ããŸããã ã€ãŸãã次ã®ããã«æžãæããããšãã§ããŸãã
public class Sample { public int _x; public static void ChangeTo(Sample self, int newValue) { self._x = newValue; } // ... } // struct public struct Sample { public int _x; public static void ChangeTo(ref Sample self, int newValue) { self._x = newValue; } // ... }
åæã«ãã¢ãŒããã¯ãã£äžã®æå³ãé€ãã°ãäœãå€ãããŸãããäž¡æ¹ã®ãªãã·ã§ã³ãã³ã³ãã€ã«ããŠãåãããã«æ©èœããããšãä¿¡ããŠãã ããã ã€ã³ã¹ã¿ã³ã¹ã¡ãœããã®å Žåã `this`ã¯æé»çã«æž¡ãããã¡ãœããã®æåã®ãã©ã¡ãŒã¿ãŒã«ãããŸããã
ç¶æ¿ã«é¢ãããã¹ãŠã®èª¬æãéçã¡ãœããã®äŸã«åºã¥ããŠæ§ç¯ãããŠããçç±ãäºåã«èª¬æããŸããå®éããã¹ãŠã®ã¡ãœããã¯éçã§ãã ã€ã³ã¹ã¿ã³ã¹ã§ã¯ãªãã ã¡ã¢ãªå ã®ã¯ã©ã¹ã®åã€ã³ã¹ã¿ã³ã¹ã«ã³ã³ãã€ã«ãããã¡ãœããã®ã€ã³ã¹ã¿ã³ã¹ã¯ãããŸããã ããã¯å€§éã®ã¡ã¢ãªãæ¶è²»ããŸããåãã¡ãœãããããããæ©èœããæ§é äœãŸãã¯ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ãžã®ãªã³ã¯ãæž¡ãæ¹ãç°¡åã§ãã
GetValueã¡ãœããã®å Žåãç¶æ³ã¯ãŸã£ããç°ãªããŸãã ç¶æ¿ãããåã®* static * `GetValue`ããªãŒããŒã©ã€ãããŠã¡ãœãããååŸããã³åå®çŸ©ããããšã¯ã§ããŸãããå€æ°ã§åäœããã³ãŒãã®éšåã§ãã` OverridedSample`ã®ã¿ãæ°ããã¡ãœãããåãåããŸãããªããžã§ã¯ããå®éã«ã©ã®åã§ãããããããªããããããŒã¹åã®ãGetValueãã®ã¿ãåŒã³åºãããšãã§ããŸãã å€æ°ãã©ã®åã§ããããã®çµæãã©ã®ç¹å®ã®ã¡ãœãããåŒã³åºãããããç解ããããã«ã次ã®ããšãã§ããŸãã
void Main() { var sample = new Sample(); var overrided = new OverridedSample(); Console.WriteLine(sample.Virtuals[Sample.GetValuePosition].DynamicInvoke(sample)); Console.WriteLine(overrided.Virtuals[Sample.GetValuePosition].DynamicInvoke(sample)); } public class Sample { public const int GetValuePosition = 0; public Delegate[] Virtuals; public int _x; public Sample() { Virtuals = new Delegate[1] { new Func<Sample, int>(GetValue) }; } public static void ChangeTo(Sample self, int newValue) { self._x = newValue; } public static int GetValue(Sample self) { return self._x; } } public class OverridedSample : Sample { public OverridedSample() : base() { Virtuals[0] = new Func<Sample, int>(GetValue); } public static new int GetValue(Sample self) { return 666; } }
ãã®äŸã§ã¯ãå®éã«ä»®æ³ã¡ãœããã®ããŒãã«ãæåã§äœæãããã®ããŒãã«å ã®ã¡ãœããã®äœçœ®ã§åŒã³åºããè¡ããŸãã äŸã®æ¬è³ªãç解ããã°ãã³ã³ãã€ã«ãããã³ãŒãã¬ãã«ã§ç¶æ¿ãã©ã®ããã«æ§ç¯ãããããå®éã«ç解ã§ããŸããã¡ãœããã¯ãä»®æ³ã¡ãœããããŒãã«ã®ã€ã³ããã¯ã¹ã§åŒã³åºãããŸãã , . VMT , , : , . , .
- CLR Book: GitHub
- 0.5.0 , PDF: GitHub Release