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