Skip to content

Commit

Permalink
jit
Browse files Browse the repository at this point in the history
  • Loading branch information
mynovelhost committed Feb 28, 2021
1 parent 3836759 commit c9f3c13
Show file tree
Hide file tree
Showing 4 changed files with 7 additions and 310 deletions.
6 changes: 3 additions & 3 deletions mk/mono.mk
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
NEEDED_MONO_VERSION := 5e9cb6d1c1de430965312927d5aed7fcb27bfa73
NEEDED_MONO_BRANCH := 2020-02
NEEDED_MONO_VERSION := 4f173da78ae55ca7f4b09565b038a823f7ffd948
NEEDED_MONO_BRANCH := 2021-02

MONO_DIRECTORY := mono
MONO_MODULE := https://github.com/mono/mono
MONO_MODULE := https://github.com/mynovelhost/mono
14 changes: 1 addition & 13 deletions tools/common/Application.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1375,19 +1375,7 @@ public bool IsInterpreted (string assembly)
// revision/testing to be used so desired.
public bool IsAOTCompiled (string assembly)
{
if (Platform == ApplePlatform.MacOSX)
throw ErrorHelper.CreateError (99, Errors.MX0099, "IsAOTCompiled isn't a valid operation for macOS apps.");

if (!UseInterpreter)
return true;

// IsAOTCompiled and IsInterpreted are not opposites: mscorlib.dll can be both:
// - mscorlib will always be processed by the AOT compiler to generate required wrapper functions for the interpreter to work
// - mscorlib might also be fully AOT-compiled (both when the interpreter is enabled and when it's not)
if (assembly == "mscorlib")
return true;

return !IsInterpreted (assembly);
return false;
}

public string AssemblyName {
Expand Down
3 changes: 1 addition & 2 deletions tools/common/Target.cs
Original file line number Diff line number Diff line change
Expand Up @@ -743,8 +743,7 @@ void GenerateIOSMain (StringWriter sw, Abi abi)
sw.WriteLine ("\tmono_sgen_mono_ilgen_init ();");
sw.WriteLine ("\tmono_ee_interp_init (NULL);");
sw.WriteLine ("\tmono_jit_set_aot_mode (MONO_AOT_MODE_INTERP);");
} else if (app.IsDeviceBuild)
sw.WriteLine ("\tmono_jit_set_aot_mode (MONO_AOT_MODE_FULL);");
}

if (assembly_location.Length > 0)
sw.WriteLine ("\txamarin_set_assembly_directories (&assembly_locations);");
Expand Down
294 changes: 2 additions & 292 deletions tools/mtouch/Target.mtouch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -941,299 +941,9 @@ public void CompilePInvokeWrappers ()

void AOTCompile ()
{
if (App.IsSimulatorBuild)
return;

if (App.Platform == ApplePlatform.MacCatalyst)
return;

// Here we create the tasks to run the AOT compiler.
foreach (var a in Assemblies) {
if (!a.IsAOTCompiled)
continue;

foreach (var abi in GetArchitectures (a.BuildTarget)) {
a.CreateAOTTask (abi);
}
}

// Group the assemblies according to their target name, and link everything together accordingly.
var grouped = Assemblies.GroupBy ((arg) => arg.BuildTargetName);
foreach (var @group in grouped) {
var name = @group.Key;
var assemblies = @group.AsEnumerable ().ToArray ();
if (assemblies.Length <= 0)
continue;

// We ensure elsewhere that all assemblies in a group have the same build target.
var build_target = assemblies [0].BuildTarget;

foreach (var abi in GetArchitectures (build_target)) {
Driver.Log (2, "Building {0} from {1}", name, string.Join (", ", assemblies.Select ((arg1) => Path.GetFileName (arg1.FileName))));

string install_name;
string compiler_output;
var compiler_flags = new CompilerFlags (this);
var link_dependencies = new List<CompileTask> ();
var infos = assemblies.Where ((asm) => asm.AotInfos.ContainsKey (abi)).Select ((asm) => asm.AotInfos [abi]).ToList ();
var aottasks = infos.Select ((info) => info.Task);
if (aottasks == null)
continue;

var existingLinkTask = infos.Where ((v) => v.LinkTask != null).Select ((v) => v.LinkTask).ToList ();
if (existingLinkTask.Count > 0) {
if (existingLinkTask.Count != infos.Count)
throw ErrorHelper.CreateError (99, Errors.MX0099, $"Not all assemblies for {name} have link tasks");
if (!existingLinkTask.All ((v) => v == existingLinkTask [0]))
throw ErrorHelper.CreateError (99, Errors.MX0099, $"Link tasks for {name} aren't all the same");

LinkWithBuildTarget (build_target, name, existingLinkTask [0], assemblies);
continue;
}

// We have to compile any source files to object files before we can link.
var sources = infos.SelectMany ((info) => info.AsmFiles);
if (sources.Count () > 0) {
foreach (var src in sources) {
// We might have to convert .s to bitcode assembly (.ll) first
var assembly = src;
BitCodeifyTask bitcode_task = null;
if (App.EnableAsmOnlyBitCode) {
bitcode_task = new BitCodeifyTask ()
{
Input = assembly,
OutputFile = Path.ChangeExtension (assembly, ".ll"),
Platform = App.Platform,
Abi = abi,
DeploymentTarget = App.DeploymentTarget,
};
bitcode_task.AddDependency (aottasks);
assembly = bitcode_task.OutputFile;
}

// Compile assembly code (either .s or .ll) to object file
var compile_task = new CompileTask
{
Target = this,
SharedLibrary = false,
InputFile = assembly,
OutputFile = Path.ChangeExtension (assembly, ".o"),
Abi = abi,
Language = bitcode_task != null ? null : "assembler",
};
compile_task.AddDependency (bitcode_task);
compile_task.AddDependency (aottasks);
link_dependencies.Add (compile_task);
}
} else {
aot_dependencies.AddRange (aottasks);
}

// Compile any .bc files to .o
foreach (var info in infos) {
foreach (var bc in info.BitcodeFiles) {
var compile_task = new CompileTask {
Target = this,
SharedLibrary = false,
InputFile = bc,
OutputFile = bc + ".o",
Abi = abi,
};
compile_task.CompilerFlags.AddOtherFlag (App.UserGccFlags);
compile_task.AddDependency (info.Task);
link_dependencies.Add (compile_task);
}
}

var arch = abi.AsArchString ();
switch (build_target) {
case AssemblyBuildTarget.StaticObject:
LinkWithTaskOutput (link_dependencies); // Any .s or .ll files from the AOT compiler (compiled to object files)
foreach (var info in infos) {
LinkWithStaticLibrary (abi, info.ObjectFiles);
}
continue; // no linking to do here.
case AssemblyBuildTarget.DynamicLibrary:
install_name = $"@rpath/lib{name}.dylib";
compiler_output = Path.Combine (App.Cache.Location, arch, $"lib{name}.dylib");
break;
case AssemblyBuildTarget.Framework:
install_name = $"@rpath/{name}.framework/{name}";
compiler_output = Path.Combine (App.Cache.Location, arch, name);
break;
default:
throw ErrorHelper.CreateError (100, Errors.MT0100, build_target);
}

CompileTask pinvoke_task;
if (pinvoke_tasks.TryGetValue (abi, out pinvoke_task))
link_dependencies.Add (pinvoke_task);

foreach (var info in infos) {
compiler_flags.AddLinkWith (info.ObjectFiles);
}

foreach (var task in link_dependencies)
compiler_flags.AddLinkWith (task.OutputFile);

foreach (var a in assemblies) {
compiler_flags.AddFrameworks (a.Frameworks, a.WeakFrameworks);
compiler_flags.AddLinkWith (a.LinkWith, a.ForceLoad);
compiler_flags.AddOtherFlag (a.LinkerFlags.ToArray ());
if (a.HasLinkWithAttributes) {
var symbols = GetRequiredSymbols (a);
switch (App.SymbolMode) {
case SymbolMode.Ignore:
break;
case SymbolMode.Code:
var tasks = GenerateReferencingSource (Path.Combine (App.Cache.Location, Path.GetFileNameWithoutExtension (a.FullPath) + "-unresolved-externals.m"), symbols);
foreach (var task in tasks)
compiler_flags.AddLinkWith (task.OutputFile);
link_dependencies.AddRange (tasks);
break;
case SymbolMode.Linker:
compiler_flags.ReferenceSymbols (symbols);
break;
default:
throw ErrorHelper.CreateError (99, Errors.MX0099, $"invalid symbol mode: {App.SymbolMode}");
}
}
}
if (App.Embeddinator)
compiler_flags.AddOtherFlag (App.UserGccFlags);
compiler_flags.LinkWithMono ();
compiler_flags.LinkWithXamarin ();
if (GetAllSymbols ().Contains ("UIApplicationMain"))
compiler_flags.AddFramework ("UIKit");

if (App.EnableLLVMOnlyBitCode) {
// The AOT compiler doesn't optimize the bitcode so clang will do it
compiler_flags.AddOtherFlag ("-fexceptions");
var optimizations = assemblies.Select ((a) => App.GetLLVMOptimizations (a)).Where ((opt) => opt != null).Distinct ().ToList ();
if (optimizations.Count == 0) {
compiler_flags.AddOtherFlag ("-O2");
} else if (optimizations.Count == 1) {
compiler_flags.AddOtherFlag (optimizations [0]);
} else {
throw ErrorHelper.CreateError (107, Errors.MT0107, string.Join (", ", assemblies.Select ((v) => v.Identity)), string.Join ("', '", optimizations));
}
}

HandleMonoNative (App, compiler_flags);

var link_task = new LinkTask ()
{
Target = this,
Abi = abi,
OutputFile = compiler_output,
InstallName = install_name,
CompilerFlags = compiler_flags,
Language = compiler_output.EndsWith (".s", StringComparison.Ordinal) ? "assembler" : null,
SharedLibrary = build_target != AssemblyBuildTarget.StaticObject,
};
link_task.AddDependency (link_dependencies);
link_task.AddDependency (aottasks);

if (App.Embeddinator) {
link_task.AddDependency (link_with_task_output);
link_task.CompilerFlags.AddLinkWith (link_with_task_output.Select ((v) => v.OutputFile));
embeddinator_tasks.Add (link_task);
}

LinkWithBuildTarget (build_target, name, link_task, assemblies);

foreach (var info in infos)
info.LinkTask = link_task;
}
}

if (App.UseInterpreter)
/* TODO: not sure? we might have to continue here, depending on
* the set of assemblies are AOT'd? */
return;

// Code in one assembly (either in a P/Invoke or a third-party library) can depend on a third-party library in another assembly.
// This means that we must always build assemblies only when all their dependent assemblies have been built, so that
// we can link (natively) with the frameworks/dylibs for those dependent assemblies.
// Fortunately we can cheat a bit, since this can (currently at least) only happen for assemblies that
// have third-party libraries. This means that we only enforce this order for any assemblies that depend
// on other assemblies that have third-party libraries.
// Example:
// * We can build System.dll and mscorlib.dll in parallel, even if System.dll depends on mscorlib.dll,
// because we know that mscorlib.dll does not have any third-party libraries.
if (Assemblies.All ((arg) => arg.HasDependencyMap)) {
var dict = Assemblies.ToDictionary ((arg) => Path.GetFileNameWithoutExtension (arg.FileName));
foreach (var asm in Assemblies) {
if (!asm.HasDependencyMap)
continue;

if (asm.BuildTarget == AssemblyBuildTarget.StaticObject)
continue;

if (Profile.IsSdkAssembly (asm.AssemblyDefinition) || Profile.IsProductAssembly (asm.AssemblyDefinition)) {
//Console.WriteLine ("SDK assembly, so skipping assembly dependency checks: {0}", Path.GetFileNameWithoutExtension (asm.FileName));
continue;
}

HashSet<Assembly> dependent_assemblies = new HashSet<Assembly> ();
foreach (var dep in asm.DependencyMap) {
Assembly dependentAssembly;
if (!dict.TryGetValue (Path.GetFileNameWithoutExtension (dep), out dependentAssembly)) {
//Console.WriteLine ("Could not find dependency '{0}' of '{1}'", dep, asm.Identity);
continue;
}
if (asm == dependentAssembly)
continue; // huh?

// Nothing can depend on anything in our SDK, nor does our SDK depend on anything else in our SDK
// So we can remove any SDK dependency
if (Profile.IsSdkAssembly (dependentAssembly.AssemblyDefinition) || Profile.IsProductAssembly (dependentAssembly.AssemblyDefinition)) {
//Console.WriteLine ("SDK assembly, so not a dependency of anything: {0}", Path.GetFileNameWithoutExtension (dependentAssembly.FileName));
continue;
}

if (!dependentAssembly.HasLinkWithAttributes) {
//Console.WriteLine ("Assembly {0} does not have LinkWith attributes, so there's nothing we can depend on.", dependentAssembly.Identity);
continue;
}

if (dependentAssembly.BuildTargetName == asm.BuildTargetName) {
//Console.WriteLine ("{0} is a dependency of {1}, but both are being built into the same target, so no dependency added.", Path.GetFileNameWithoutExtension (dep), Path.GetFileNameWithoutExtension (asm.FileName));
continue;
}

//Console.WriteLine ("Added {0} as a dependency of {1}", Path.GetFileNameWithoutExtension (dep), Path.GetFileNameWithoutExtension (asm.FileName));
dependent_assemblies.Add (dependentAssembly);
}

// Circular dependencies shouldn't happen, but still make sure, since it's technically possible
// for users to do it.
foreach (var abi in GetArchitectures (asm.BuildTarget)) {
var target_task = asm.AotInfos [abi].LinkTask;
var dependent_tasks = dependent_assemblies.Select ((v) => v.AotInfos [abi].LinkTask);

var stack = new Stack<BuildTask> ();
foreach (var dep in dependent_tasks) {
stack.Clear ();
stack.Push (target_task);
if (target_task == dep || IsCircularTask (target_task, stack, dep)) {
Driver.Log ("Found circular task.");
Driver.Log ("Task {0} (with output {1}) depends on:", target_task.GetType ().Name, target_task.Outputs.First ());
stack = new Stack<BuildTask> (stack.Reverse ());
while (stack.Count > 0) {
var node = stack.Pop ();
Driver.Log (" -> {0} (Output: {1})", node.GetType ().Name, node.Outputs.First ());
}
} else {
target_task.AddDependency (dep);
target_task.CompilerFlags.AddLinkWith (dep.OutputFile);
}
}
}
}
}

}

bool IsCircularTask (BuildTask root, Stack<BuildTask> stack, BuildTask task)
{
stack.Push (task);
Expand Down

0 comments on commit c9f3c13

Please sign in to comment.