0775292a10665800551ee99ffbbc20a515efa8bd
[mono.git] / tools / offsets-tool / MonoAotOffsetsDumper.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text.RegularExpressions;
6 using CppSharp.AST;
7 using CppSharp.AST.Extensions;
8 using CppSharp.Parser;
9
10 namespace CppSharp
11 {
12     /**
13      * This tool dumps the offsets of structures used in the Mono VM needed
14      * by the AOT compiler for cross-compiling code to target platforms
15      * different than the host the compiler is being invoked on.
16      * 
17      * It takes two arguments: the path to your clone of the Mono repo and
18      * the path to the root of Android NDK.
19      */
20     static class MonoAotOffsetsDumper
21     {
22         static string MonoDir = @"";
23
24         static List<string> Abis = new List<string> ();
25         static string OutputDir;
26
27         static string MonodroidDir = @"";
28         static string AndroidNdkPath = @"";
29         static string MaccoreDir = @"";
30         static string TargetDir = @"";
31
32         public enum TargetPlatform
33         {
34             Android,
35             iOS,
36             WatchOS,
37         }
38
39         public class Target
40         {
41             public Target()
42             {
43                 Defines = new List<string>();
44                 Arguments = new List<string>();
45             }
46
47             public Target(Target target)
48             {
49                 Platform = target.Platform;
50                 Triple = target.Triple;
51                 Build = target.Build;
52                 Defines = target.Defines;
53                 Arguments = target.Arguments;
54             }
55
56             public TargetPlatform Platform;
57             public string Triple;
58             public string Build;            
59             public List<string> Defines;
60             public List<string> Arguments;
61         };
62
63         public static List<Target> Targets = new List<Target>();
64
65         public static IEnumerable<Target> AndroidTargets
66         {
67             get { return Targets.Where ((t) => t.Platform == TargetPlatform.Android); }
68         }
69
70         public static IEnumerable<Target> DarwinTargets
71         {
72             get
73             {
74                 return Targets.Where ((t) => t.Platform == TargetPlatform.iOS ||
75                     t.Platform == TargetPlatform.WatchOS);
76             }
77         }
78
79         public static IEnumerable<Target> iOSTargets
80         {
81             get
82             {
83                 return Targets.Where ((t) => t.Platform == TargetPlatform.iOS);
84             }
85         }
86
87         public static void SetupAndroidTargets()
88         {
89             Targets.Add (new Target {
90                 Platform = TargetPlatform.Android,
91                 Triple = "i686-none-linux-android",
92                 Defines = { "TARGET_X86" }
93             });
94
95             Targets.Add (new Target {
96                 Platform = TargetPlatform.Android,
97                 Triple = "x86_64-none-linux-android",
98                 Defines = { "TARGET_AMD64" }
99             });            
100
101             Targets.Add (new Target {
102                 Platform = TargetPlatform.Android,
103                 Triple = "armv5-none-linux-androideabi",
104                 Defines = { "TARGET_ARM", "ARM_FPU_VFP", "HAVE_ARMV5" }
105             });
106
107             Targets.Add (new Target {
108                 Platform = TargetPlatform.Android,
109                 Triple = "armv7-none-linux-androideabi",
110                 Defines = { "TARGET_ARM", "ARM_FPU_VFP", "HAVE_ARMV5", "HAVE_ARMV6",
111                     "HAVE_ARMV7"
112                 }
113             });
114
115             Targets.Add (new Target {
116                 Platform = TargetPlatform.Android,
117                 Triple = "aarch64-v8a-linux-android",
118                 Defines = { "TARGET_ARM64" }
119             });            
120
121             /*Targets.Add(new Target {
122                     Platform = TargetPlatform.Android,
123                     Triple = "mipsel-none-linux-android",
124                     Defines = { "TARGET_MIPS", "__mips__" }
125                 });*/
126
127             foreach (var target in AndroidTargets)
128                 target.Defines.AddRange (new string[] { "PLATFORM_ANDROID",
129                     "TARGET_ANDROID", "MONO_CROSS_COMPILE", "USE_MONO_CTX"
130                 });
131         }
132
133         public static void SetupiOSTargets()
134         {
135             Targets.Add(new Target {
136                 Platform = TargetPlatform.iOS,
137                 Triple = "arm-apple-darwin10",
138                 Build = "target7",
139                 Defines = { "TARGET_ARM", "ARM_FPU_VFP", "HAVE_ARMV5" }
140             });
141
142             Targets.Add(new Target {
143                 Platform = TargetPlatform.iOS,
144                 Triple = "aarch64-apple-darwin10",
145                 Build = "target64",                    
146                 Defines = { "TARGET_ARM64" }
147             });
148
149             foreach (var target in iOSTargets) {
150                 target.Defines.AddRange (new string[] { "PLATFORM_DARWIN",
151                     "TARGET_IOS", "TARGET_MACH", "MONO_CROSS_COMPILE", "USE_MONO_CTX",
152                     "_XOPEN_SOURCE"
153                 });
154             }
155
156             Targets.Add(new Target {
157                 Platform = TargetPlatform.WatchOS,
158                 Triple = "armv7k-apple-darwin",
159                 Build = "targetwatch",
160                 Defines = { "TARGET_ARM", "ARM_FPU_VFP", "HAVE_ARMV5" }
161             });
162
163             foreach (var target in DarwinTargets) {
164                 target.Defines.AddRange (new string[] { "PLATFORM_DARWIN",
165                     "TARGET_IOS", "TARGET_MACH", "MONO_CROSS_COMPILE", "USE_MONO_CTX",
166                     "_XOPEN_SOURCE"
167                 });
168             }
169         }
170
171         static bool GetParentSubDirectoryPath(string parent, out string subdir)
172         {
173             var directory = Directory.GetParent(Directory.GetCurrentDirectory());
174
175             while (directory != null) {
176                 var path = Path.Combine(directory.FullName, parent);
177
178                 if (Directory.Exists (path)) {
179                     subdir = path;
180                     return true;
181                 }
182
183                 directory = directory.Parent;
184             }
185
186             subdir = null;
187             return false;
188         }
189
190         public static void Main(string[] args)
191         {
192             ParseCommandLineArgs(args);
193
194             string monodroidDir;
195             if (!Directory.Exists (MonodroidDir) &&
196                 GetParentSubDirectoryPath ("monodroid", out monodroidDir)) {
197                 MonodroidDir = Path.Combine (monodroidDir);
198             }
199
200             if (Directory.Exists (MonodroidDir))
201                 SetupAndroidTargets();
202
203             string maccoreDir;
204             if (!Directory.Exists (MaccoreDir) &&
205                 GetParentSubDirectoryPath ("maccore", out maccoreDir)) {
206                 MaccoreDir = Path.Combine (maccoreDir);
207             }
208
209             if (Directory.Exists(MaccoreDir))
210                 SetupiOSTargets();
211
212             foreach (var target in Targets)
213              {
214                 if (Abis.Any() && !Abis.Any (target.Triple.Contains))
215                     continue;
216                 
217                 Console.WriteLine();
218                 Console.WriteLine("Processing triple: {0}", target.Triple);
219
220                 var options = new DriverOptions();
221
222                 var driver = new Driver(options);
223
224                 Setup(driver, target);
225                 driver.Setup();
226
227                 BuildParseOptions(driver, target);
228                 if (!driver.ParseCode())
229                     return;
230
231                 Dump(driver.Context.ASTContext, driver.Context.TargetInfo, target);
232             }
233         }
234
235         static void BuildParseOptions(Driver driver, Target target)
236         {
237             foreach (var header in driver.Options.Headers)
238             {
239                 var source = driver.Project.AddFile(header);
240                 source.Options = driver.BuildParserOptions(source);
241
242                 if (header.Contains ("mini"))
243                     continue;
244
245                 source.Options.AddDefines ("HAVE_SGEN_GC");
246                 source.Options.AddDefines ("HAVE_MOVING_COLLECTOR");
247             }
248         }
249
250         static string GetAndroidNdkPath()
251         {
252             if (!String.IsNullOrEmpty (AndroidNdkPath))
253                 return AndroidNdkPath;
254
255             // Find the Android NDK's path from Monodroid's config.
256             var configFile = Path.Combine(MonodroidDir, "env.config");
257             if (!File.Exists(configFile))
258                 throw new Exception("Expected a valid Monodroid environment config file at " + configFile);
259
260             var config = File.ReadAllText(configFile);
261             var match = Regex.Match(config, @"ANDROID_NDK_PATH\s*:=\s(.*)");
262             return match.Groups[1].Value.Trim();
263         }
264
265         static void ParseCommandLineArgs(string[] args)
266         {
267             var showHelp = false;
268
269             var options = new Mono.Options.OptionSet () {
270                 { "abi=", "ABI triple to generate", v => Abis.Add(v) },
271                 { "o|out=", "output directory", v => OutputDir = v },
272                 { "maccore=", "include directory", v => MaccoreDir = v },
273                 { "monodroid=", "top monodroid directory", v => MonodroidDir = v },
274                 { "android-ndk=", "Path to Android NDK", v => AndroidNdkPath = v },
275                 { "targetdir=", "Path to the directory containing the mono build", v =>TargetDir = v },
276                 { "mono=", "include directory", v => MonoDir = v },
277                 { "h|help",  "show this message and exit",  v => showHelp = v != null },
278             };
279
280             try {
281                 options.Parse (args);
282             }
283             catch (Mono.Options.OptionException e) {
284                 Console.WriteLine (e.Message);
285                 Environment.Exit(0);
286             }
287
288             if (showHelp)
289             {
290                 // Print usage and exit.
291                 Console.WriteLine("{0} <options>",
292                     AppDomain.CurrentDomain.FriendlyName);
293                 options.WriteOptionDescriptions (Console.Out);
294                 Environment.Exit(0);
295             }
296         }
297
298         static void Setup(Driver driver, Target target)
299         {
300             var options = driver.Options;
301             options.DryRun = true;
302             options.LibraryName = "Mono";
303
304             var parserOptions = driver.ParserOptions;
305             parserOptions.Verbose = false;
306             parserOptions.MicrosoftMode = false;
307             parserOptions.AddArguments("-xc");
308             parserOptions.AddArguments("-std=gnu99");
309             parserOptions.AddDefines("CPPSHARP");
310
311             foreach (var define in target.Defines)
312                 parserOptions.AddDefines(define);
313
314             SetupToolchainPaths(driver, target);
315
316             SetupMono(driver, target);
317         }
318
319         static void SetupMono(Driver driver, Target target)
320         {
321             string targetBuild;
322             switch (target.Platform) {
323             case TargetPlatform.Android:
324                 if (TargetDir == "") {
325                     Console.Error.WriteLine ("The --targetdir= option is required when targeting android.");
326                     Environment.Exit (1);
327                 }
328                 if (MonoDir == "") {
329                     Console.Error.WriteLine ("The --mono= option is required when targeting android.");
330                     Environment.Exit (1);
331                 }
332                 if (Abis.Count != 1) {
333                     Console.Error.WriteLine ("Exactly one --abi= argument is required when targeting android.");
334                     Environment.Exit (1);
335                 }
336                 targetBuild = TargetDir;
337                 break;
338             case TargetPlatform.WatchOS:
339             case TargetPlatform.iOS: {
340                 if (!string.IsNullOrEmpty (TargetDir)) {
341                     targetBuild = TargetDir;
342                 } else {
343                     string targetPath = Path.Combine (MaccoreDir, "builds");
344                     if (!Directory.Exists (MonoDir))
345                         MonoDir = Path.GetFullPath (Path.Combine (targetPath, "../../mono"));
346                     targetBuild = Path.Combine(targetPath, target.Build);
347                 }
348                 break;
349             }
350             default:
351                 throw new ArgumentOutOfRangeException ();
352             }
353
354             if (!Directory.Exists(targetBuild))
355                 throw new Exception(string.Format("Could not find the target build directory: {0}", targetBuild));
356
357             var includeDirs = new[]
358             {
359                 targetBuild,
360                 Path.Combine(targetBuild, "eglib", "src"),
361                 MonoDir,
362                 Path.Combine(MonoDir, "mono"),
363                 Path.Combine(MonoDir, "mono", "mini"),
364                 Path.Combine(MonoDir, "eglib", "src")
365             };
366
367             foreach (var inc in includeDirs)
368                 driver.ParserOptions.AddIncludeDirs(inc);
369
370             var filesToParse = new[]
371             {
372                 Path.Combine(MonoDir, "mono", "metadata", "metadata-cross-helpers.c"),
373                 Path.Combine(MonoDir, "mono", "mini", "mini-cross-helpers.c"),
374             };
375
376             foreach (var file in filesToParse)
377                 driver.Options.Headers.Add(file);
378         }
379
380         static void SetupMSVC(Driver driver, string triple)
381         {
382             var parserOptions = driver.ParserOptions;
383
384             parserOptions.Abi = Parser.AST.CppAbi.Microsoft;
385             parserOptions.MicrosoftMode = true;
386
387             var systemIncludeDirs = new[]
388             {
389                 @"C:\Program Files (x86)\Windows Kits\8.1\Include\um",
390                 @"C:\Program Files (x86)\Windows Kits\8.1\Include\shared"
391             };
392
393             foreach (var inc in systemIncludeDirs)
394                 parserOptions.AddSystemIncludeDirs(inc);
395
396             parserOptions.AddDefines("HOST_WIN32");
397         }
398
399         static void SetupToolchainPaths(Driver driver, Target target)
400         {
401             switch (target.Platform) {
402             case TargetPlatform.Android:
403                 SetupAndroidNDK(driver, target);
404                 break;
405             case TargetPlatform.iOS:
406             case TargetPlatform.WatchOS:
407                 SetupXcode(driver, target);
408                 break;
409             default:
410                 throw new ArgumentOutOfRangeException ();
411             }
412         }        
413
414         static string GetArchFromTriple(string triple)
415         {
416             if (triple.Contains("mips"))
417                 return "mips";
418
419             if (triple.Contains("arm64") || triple.Contains("aarch64"))
420                 return "arm64";
421
422             if (triple.Contains("arm"))
423                 return "arm";
424
425             if (triple.Contains("i686"))
426                 return "x86";
427
428             if (triple.Contains("x86_64"))
429                 return "x86_64";
430
431             throw  new Exception("Unknown architecture from triple: " + triple);
432         }
433
434         static string GetXcodeToolchainPath()
435         {
436             var toolchains = Directory.EnumerateDirectories("/Applications", "Xcode*")
437                 .ToList();
438             toolchains.Sort();
439
440             var toolchainPath = toolchains.LastOrDefault();
441             if (toolchainPath == null)
442                 throw new Exception("Could not find a valid Xcode SDK");
443
444             return toolchainPath;
445         }
446
447         static string GetXcodeBuiltinIncludesFolder()
448         {
449             var toolchainPath = GetXcodeToolchainPath();
450
451             var toolchains = Directory.EnumerateDirectories(Path.Combine(toolchainPath,
452                 "Contents/Developer/Toolchains")).ToList();
453             toolchains.Sort();
454
455             toolchainPath = toolchains.LastOrDefault();
456             if (toolchainPath == null)
457                 throw new Exception("Could not find a valid Xcode toolchain");
458
459             var includePaths = Directory.EnumerateDirectories(Path.Combine(toolchainPath,
460                 "usr/lib/clang")).ToList();
461             var includePath = includePaths.LastOrDefault();
462
463             if (includePath == null)
464                 throw new Exception("Could not find a valid Clang include folder");
465
466             return Path.Combine(includePath, "include");
467         }
468
469         static string GetXcodeiOSIncludesFolder()
470         {
471             var toolchainPath = GetXcodeToolchainPath();
472
473             var sdkPaths = Directory.EnumerateDirectories(Path.Combine(toolchainPath,
474                 "Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs")).ToList();
475             var sdkPath = sdkPaths.LastOrDefault();
476
477             if (sdkPath == null)
478                 throw new Exception("Could not find a valid iPhone SDK");
479
480             return Path.Combine(sdkPath, "usr/include");
481         }
482
483         static string GetXcodeWatchOSIncludesFolder()
484         {
485             var toolchainPath = GetXcodeToolchainPath();
486
487             var sdkPaths = Directory.EnumerateDirectories(Path.Combine(toolchainPath,
488                 "Contents/Developer/Platforms/WatchOS.platform/Developer/SDKs")).ToList();
489             var sdkPath = sdkPaths.LastOrDefault();
490
491             if (sdkPath == null)
492                 throw new Exception("Could not find a valid WatchOS SDK");
493
494             return Path.Combine(sdkPath, "usr/include");
495         }
496
497         static void SetupXcode(Driver driver, Target target)
498         {
499             var parserOptions = driver.ParserOptions;
500
501             var builtinsPath = GetXcodeBuiltinIncludesFolder();
502             string includePath;
503
504             switch (target.Platform) {
505             case TargetPlatform.iOS:
506                 includePath = GetXcodeiOSIncludesFolder();
507                 break;
508             case TargetPlatform.WatchOS:
509                 includePath = GetXcodeWatchOSIncludesFolder();
510                 break;
511             default:
512                 throw new ArgumentOutOfRangeException ();
513             }
514
515             parserOptions.AddSystemIncludeDirs(builtinsPath);
516             parserOptions.AddSystemIncludeDirs(includePath);
517
518             parserOptions.NoBuiltinIncludes = true;
519             parserOptions.NoStandardIncludes = true;
520             parserOptions.TargetTriple = target.Triple;
521         }
522
523         static string GetAndroidHostToolchainPath()
524         {
525             var androidNdkPath = GetAndroidNdkPath ();
526             var toolchains = Directory.EnumerateDirectories(
527                 Path.Combine(androidNdkPath, "toolchains"), "llvm*").ToList();
528             toolchains.Sort();
529
530             var toolchainPath = toolchains.LastOrDefault();
531             if (toolchainPath == null)
532                 throw new Exception("Could not find a valid NDK host toolchain");
533
534             toolchains = Directory.EnumerateDirectories(Path.Combine(toolchainPath,
535                 "prebuilt")).ToList();
536             toolchains.Sort();
537
538             toolchainPath = toolchains.LastOrDefault();
539             if (toolchainPath == null)
540                 throw new Exception("Could not find a valid NDK host toolchain");
541
542             return toolchainPath;
543         }
544
545         static string GetAndroidBuiltinIncludesFolder()
546         {
547             var toolchainPath = GetAndroidHostToolchainPath();
548
549             string clangToolchainPath = Path.Combine(toolchainPath, "lib64", "clang");
550             if (!Directory.Exists (clangToolchainPath))
551                 clangToolchainPath = Path.Combine(toolchainPath, "lib", "clang");
552
553             string includePath = null;
554             if (Directory.Exists (clangToolchainPath)) {
555                 var includePaths = Directory.EnumerateDirectories(clangToolchainPath).ToList();
556                 includePath = includePaths.LastOrDefault();
557             }
558             if (includePath == null)
559                 throw new Exception("Could not find a valid Clang include folder");
560
561             return Path.Combine(includePath, "include");
562         }
563
564         static void SetupAndroidNDK(Driver driver, Target target)
565         {
566             var options = driver.Options;
567             var parserOptions = driver.ParserOptions;
568
569             var builtinsPath = GetAndroidBuiltinIncludesFolder();
570             parserOptions.AddSystemIncludeDirs(builtinsPath);
571
572             var androidNdkRoot = GetAndroidNdkPath ();
573             const int androidNdkApiLevel = 21;
574
575             var toolchainPath = Path.Combine(androidNdkRoot, "platforms",
576                 "android-" + androidNdkApiLevel, "arch-" + GetArchFromTriple(target.Triple),
577                 "usr", "include");
578             parserOptions.AddSystemIncludeDirs(toolchainPath);
579
580             parserOptions.NoBuiltinIncludes = true;
581             parserOptions.NoStandardIncludes = true;
582             parserOptions.TargetTriple = target.Triple;
583         }
584
585         static uint GetTypeAlign(ParserTargetInfo target, ParserIntType type)
586         {
587             switch (type)
588             {
589                 case ParserIntType.SignedChar:
590                 case ParserIntType.UnsignedChar:
591                     return target.CharAlign;
592                 case ParserIntType.SignedShort:
593                 case ParserIntType.UnsignedShort:
594                     return target.ShortAlign;
595                 case ParserIntType.SignedInt:
596                 case ParserIntType.UnsignedInt:
597                     return target.IntAlign;
598                 case ParserIntType.SignedLong:
599                 case ParserIntType.UnsignedLong:
600                     return target.LongAlign;
601                 case ParserIntType.SignedLongLong:
602                 case ParserIntType.UnsignedLongLong:
603                     return target.LongLongAlign;
604                 default:
605                     throw new Exception("Type has no alignment");
606             }
607         }
608
609         static uint GetTypeSize(ParserTargetInfo target, ParserIntType type)
610         {
611             switch (type)
612             {
613                 case ParserIntType.SignedChar:
614                 case ParserIntType.UnsignedChar:
615                     return target.CharWidth;
616                 case ParserIntType.SignedShort:
617                 case ParserIntType.UnsignedShort:
618                     return target.ShortWidth;
619                 case ParserIntType.SignedInt:
620                 case ParserIntType.UnsignedInt:
621                     return target.IntWidth;
622                 case ParserIntType.SignedLong:
623                 case ParserIntType.UnsignedLong:
624                     return target.LongWidth;
625                 case ParserIntType.SignedLongLong:
626                 case ParserIntType.UnsignedLongLong:
627                     return target.LongLongWidth;
628                 default:
629                     throw new Exception("Type has no size");
630             }
631         }
632
633         static string GetTargetPlatformDefine(TargetPlatform target)
634         {
635             switch (target) {
636             case TargetPlatform.Android:
637                 return "TARGET_ANDROID";
638             case TargetPlatform.iOS:
639                 return "TARGET_IOS";
640             case TargetPlatform.WatchOS:
641                 return "TARGET_WATCHOS";
642             default:
643                 throw new ArgumentOutOfRangeException ();
644             }
645         }
646
647         static void Dump(ASTContext ctx, ParserTargetInfo targetInfo, Target target)
648         {
649             var targetFile = target.Triple;
650
651             if (!string.IsNullOrEmpty (OutputDir))
652                 targetFile = Path.Combine (OutputDir, targetFile);
653
654             targetFile += ".h";
655
656             using (var writer = new StreamWriter(targetFile))
657             //using (var writer = Console.Out)
658             {
659                 writer.WriteLine("#ifndef USED_CROSS_COMPILER_OFFSETS");
660                 writer.WriteLine("#ifdef {0}", target.Defines[0]);
661                 writer.WriteLine ("#ifdef {0}", GetTargetPlatformDefine (target.Platform));
662                 writer.WriteLine("#ifndef HAVE_BOEHM_GC");
663                 writer.WriteLine("#define HAS_CROSS_COMPILER_OFFSETS");
664                 writer.WriteLine("#if defined (USE_CROSS_COMPILE_OFFSETS) || defined (MONO_CROSS_COMPILE)");
665                 writer.WriteLine("#if !defined (DISABLE_METADATA_OFFSETS)");
666                 writer.WriteLine("#define USED_CROSS_COMPILER_OFFSETS");
667
668                 DumpAligns(writer, targetInfo);
669                 DumpSizes(writer, targetInfo);
670                 DumpMetadataOffsets(writer, ctx, target);
671
672                 writer.WriteLine("#endif //disable metadata check");
673
674                 DumpJITOffsets(writer, ctx);
675
676                 writer.WriteLine("#endif //cross compiler checks");
677                 writer.WriteLine("#endif //gc check");
678                 writer.WriteLine("#endif //os check");
679                 writer.WriteLine("#endif //arch check");
680                 writer.WriteLine("#endif //USED_CROSS_COMPILER_OFFSETS check");
681             }
682
683             Console.WriteLine("Generated offsets file: {0}", targetFile);
684         }
685
686         static void DumpAligns(TextWriter writer, ParserTargetInfo target)
687         {
688             var aligns = new[]
689             {
690                 new { Name = "gint8", Align = target.CharAlign},
691                 new { Name = "gint16", Align = target.ShortAlign},
692                 new { Name = "gint32", Align = target.IntAlign},
693                 new { Name = "gint64", Align = GetTypeAlign(target, target.Int64Type)},
694                 new { Name = "float", Align = target.FloatAlign},
695                 new { Name = "double", Align = target.DoubleAlign},
696                 new { Name = "gpointer", Align = GetTypeAlign(target, target.IntPtrType)},
697             };
698
699             // Write the alignment info for the basic types.
700             foreach (var align in aligns)
701                 writer.WriteLine("DECL_ALIGN2({0},{1})", align.Name, align.Align / 8);
702         }
703
704         static void DumpSizes(TextWriter writer, ParserTargetInfo target)
705         {
706             var sizes = new[]
707             {
708                 new { Name = "gint8", Size = target.CharWidth},
709                 new { Name = "gint16", Size = target.ShortWidth},
710                 new { Name = "gint32", Size = target.IntWidth},
711                 new { Name = "gint64", Size = GetTypeSize(target, target.Int64Type)},
712                 new { Name = "float", Size = target.FloatWidth},
713                 new { Name = "double", Size = target.DoubleWidth},
714                 new { Name = "gpointer", Size = GetTypeSize(target, target.IntPtrType)},
715             };
716
717             // Write the size info for the basic types.
718             foreach (var size in sizes)
719                 writer.WriteLine("DECL_SIZE2({0},{1})", size.Name, size.Size / 8);
720         }
721
722         static Class GetClassFromTypedef(ITypedDecl typedef)
723         {
724             var type = typedef.Type.Desugar() as TagType;
725             if (type == null)
726                 return null;
727
728             var @class = type.Declaration as Class;
729
730             return @class.IsIncomplete ?
731                 (@class.CompleteDeclaration as Class) : @class; 
732         }
733
734         static void DumpClasses(TextWriter writer, ASTContext ctx, IEnumerable<string> types,
735             bool optional = false)
736         {
737             foreach (var @struct in types)
738             {
739                 var @class = ctx.FindCompleteClass(@struct);
740                 if (@class == null)
741                     @class = ctx.FindCompleteClass("_" + @struct);
742
743                 if (@class == null)
744                 {
745                     var typedef = ctx.FindTypedef(@struct).FirstOrDefault(
746                         decl => !decl.IsIncomplete);
747
748                     if (typedef != null)
749                         @class = GetClassFromTypedef(typedef);
750                 }
751
752                 if (@class == null && optional)
753                     continue;
754
755                 if (@class == null)
756                     throw new Exception("Expected to find struct definition for " + @struct);
757
758                 DumpStruct(writer, @class);
759             }
760         }
761
762         static void DumpMetadataOffsets(TextWriter writer, ASTContext ctx, Target target)
763         {
764             var types = new List<string>
765             {
766                 "MonoObject",
767                 "MonoObjectHandlePayload",
768                 "MonoClass",
769                 "MonoVTable",
770                 "MonoDelegate",
771                 "MonoInternalThread",
772                 "MonoMulticastDelegate",
773                 "MonoTransparentProxy",
774                 "MonoRealProxy",
775                 "MonoRemoteClass",
776                 "MonoArray",
777                 "MonoArrayBounds",
778                 "MonoSafeHandle",
779                 "MonoHandleRef",
780                 "MonoComInteropProxy",
781                 "MonoString",
782                 "MonoException",
783                 "MonoTypedRef",
784                 "MonoThreadsSync",
785                 "SgenThreadInfo",
786                 "SgenClientThreadInfo"
787             };
788
789             DumpClasses(writer, ctx, types);
790         }
791
792         static void DumpJITOffsets(TextWriter writer, ASTContext ctx)
793         {
794             writer.WriteLine("#ifndef DISABLE_JIT_OFFSETS");
795             writer.WriteLine("#define USED_CROSS_COMPILER_OFFSETS");
796
797             var types = new[]
798             {
799                 "MonoLMF",
800                 "MonoMethodRuntimeGenericContext",
801                 "MonoJitTlsData",
802                 "MonoGSharedVtMethodRuntimeInfo",
803                 "MonoContinuation",
804                 "MonoContext",
805                 "MonoDelegateTrampInfo",
806             };
807
808             DumpClasses(writer, ctx, types);
809
810             var optionalTypes = new[]
811             {
812                 "GSharedVtCallInfo",
813                 "SeqPointInfo",
814                 "DynCallArgs", 
815                 "MonoLMFTramp",
816                 "InterpMethodArguments",
817             };
818
819             DumpClasses(writer, ctx, optionalTypes, optional: true);
820
821             writer.WriteLine("#endif //disable jit check");
822         }
823
824         static void DumpStruct(TextWriter writer, Class @class)
825         {
826             var name = @class.Name;
827             if (name.StartsWith ("_", StringComparison.Ordinal))
828                 name = name.Substring (1);
829
830             foreach (var field in @class.Fields)
831             {
832                 if (field.IsBitField) continue;
833
834                 if (name == "SgenThreadInfo" && field.Name == "regs")
835                     continue;
836
837                 var layout = @class.Layout.Fields.First(f => f.FieldPtr == field.OriginalPtr);
838
839                 writer.WriteLine("DECL_OFFSET2({0},{1},{2})", name, field.Name,
840                     layout.Offset);
841             }
842         }
843     }
844 }