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