static void EmitUnboxAny(TypeMapEntry tme) { Emit(tme.instrs); Emit("box " + tme.ilty); Emit("unbox.any " + tme.ilty); EmitPrint(tme); }
static string EmitLocal(TypeMapEntry tme, string prefix) { string varname = "'" + prefix + "_" + tme.ty + "'"; Emit(".locals(" + tme.ilty + " " + varname + ")"); return(varname); }
static void EmitInitObj(TypeMapEntry tme) { string dest = EmitLocal(tme); Emit("ldloca " + dest); Emit("initobj " + tme.ilty); Emit("ldloc " + dest); EmitPrint(tme); }
static void EmitStObj(TypeMapEntry tme) { string varname = EmitLocal(tme); Emit("ldloca " + varname); Emit(tme.instrs); Emit("stobj " + tme.ilty); Emit("ldloc " + varname); EmitPrint(tme); }
public void TypeMapConstructorTest() { FileType ft = new FileType("binary"); TypeMapEntry mapping = new TypeMapEntry(ft, "//depot/main/..."); FormSpec spec = null; TypeMap target = new TypeMap(mapping, spec); Assert.IsNotNull(target); Assert.AreEqual(target.Mapping.FileType.BaseType, BaseFileType.Binary); Assert.AreEqual(target.Mapping.Path, "//depot/main/..."); }
static void EmitCpObj(TypeMapEntry tme) { string src = EmitLocal(tme, "S"); string dest = EmitLocal(tme, "D"); Emit(tme.instrs); Emit("stloc " + src); Emit("ldloca " + dest); Emit("ldloca " + src); Emit("cpobj " + tme.ilty); Emit("ldloc " + dest); EmitPrint(tme); }
public void MappingTest() { FileType ft = new FileType("binary"); FileType ft1 = new FileType("apple"); FileType ft2 = new FileType("text"); TypeMapEntry mapping = new TypeMapEntry(ft, "//depot/main/..."); TypeMapEntry mapping1 = new TypeMapEntry(ft1, "//depot/dev/..."); TypeMapEntry mapping2 = new TypeMapEntry(ft2, "//depot/rel/..."); TypeMap target = new TypeMap(); target.Add(mapping); target.Add(mapping1); target.Add(mapping2); Assert.IsNotNull(target); Assert.AreEqual(target.Count, 3); Assert.AreEqual(target[1].Path, "//depot/dev/..."); }
static void EmitUnboxAnyFail(TypeMapEntry tme) { string l1 = GenLabel(); string l2 = GenLabel(); EmitOpenBrace(".try"); Emit("newobj instance void [mscorlib]System.Object::.ctor()"); Emit("unbox.any " + tme.ilty); Emit("pop"); Emit("leave " + l1); EmitCloseBrace(); EmitOpenBrace("catch [mscorlib]System.InvalidCastException"); Emit("pop"); EmitPrintString("downcast failed\\n"); Emit("leave " + l2); EmitCloseBrace(); Emit(l1 + ":"); EmitPrintString("downcast succeeded\\n"); Emit(l2 + ":"); }
static void EmitStElemAny(TypeMapEntry tme) { Emit("ldc.i4 10 newarr " + tme.ilty); Emit("dup"); Emit("ldc.i4 0"); Emit(tme.instrs); Emit("stelem.any " + tme.ilty); Emit("ldc.i4 0"); if (tme.isref) { Emit("ldelem.ref"); } else { Emit("ldelem.any " + tme.ilty); Emit("box " + tme.ilty); } EmitWriteLine(); }
static void EmitLdElemAny(TypeMapEntry tme) { Emit("ldc.i4 10 newarr " + tme.ilty); Emit("dup"); Emit("ldc.i4 0"); if (tme.isref) { Emit(tme.instrs); Emit("stelem.ref"); } else { Emit("ldelema " + tme.ilty); Emit(tme.instrs); Emit("stobj " + tme.ilty); } Emit("ldc.i4 0"); Emit("ldelem.any " + tme.ilty); EmitPrint(tme); }
static void EmitBoxAny(TypeMapEntry tme) { Emit(tme.instrs); Emit("box " + tme.ilty); EmitWriteLine(); }
static void EmitPrint(TypeMapEntry tme) { Emit("box " + tme.ilty); EmitWriteLine(); }
static int Main(string[] args) { string testname; string typename; TypeMapEntry[] types = typemap; TestMapEntry[] tests = testmap; filename = "test.il"; foreach (string a in args) { int len = a.Length; if (len >= 2 && (a[0] == '/' || a[0] == '-')) { switch (Char.ToUpper(a[1])) { case 'I': testname = a.Substring(3); if (testname != "*") { tests = new TestMapEntry[1]; try { tests[0] = LookupTest(testname); } catch (NotFound) { Console.WriteLine("No such test: " + testname); return(1); } } break; case 'T': typename = a.Substring(3); if (typename != "*") { types = new TypeMapEntry[1]; try { types[0] = LookupType(typename); } catch (NotFound) { Console.WriteLine("No such type: " + typename); return(1); } } break; case 'F': filename = a.Substring(3); break; case 'X': System.AppDomain.CurrentDomain.ExecuteAssembly("ilasm"); break; case '?': Usage(); return(0); } } } FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None); outstream = new StreamWriter(fs); Console.Write("Generating IL to " + filename + "..."); EmitHeader(); foreach (TestMapEntry test in tests) { EmitPrintString("********************************* " + test.description + " *************************\\n"); foreach (TypeMapEntry type in types) { EmitPrintString(" on type " + type.ty + ": "); test.emitter(type); } } EmitFooter(); outstream.Close(); Console.Write("done.\n"); return(0); }
static int Main(string[] args) { string testname; string typename; TypeMapEntry[] types = typemap; TestMapEntry[] tests = testmap; filename = "test.il"; foreach (string a in args) { int len = a.Length; if (len >= 2 && (a[0] == '/' || a[0] == '-')) { switch (Char.ToUpper(a[1])) { case 'I': testname = a.Substring(3); if (testname != "*") { tests = new TestMapEntry[1]; try { tests[0] = LookupTest(testname); } catch (NotFound) { Console.WriteLine("No such test: " + testname); return 1; } } break; case 'T': typename = a.Substring(3); if (typename != "*") { types = new TypeMapEntry[1]; try { types[0] = LookupType(typename); } catch (NotFound) { Console.WriteLine("No such type: " + typename); return 1; } } break; case 'F': filename = a.Substring(3); break; case 'X': System.AppDomain.CurrentDomain.ExecuteAssembly("ilasm"); break; case '?': Usage(); return 0; } } } FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.None); outstream = new StreamWriter(fs); Console.Write("Generating IL to " + filename + "..."); EmitHeader(); foreach (TestMapEntry test in tests) { EmitPrintString("********************************* " + test.description + " *************************\\n"); foreach (TypeMapEntry type in types) { EmitPrintString(" on type " + type.ty + ": "); test.emitter(type); } } EmitFooter(); outstream.Close(); Console.Write("done.\n"); return 0; }
static void EmitNewObj(TypeMapEntry tme) { Emit(tme.instrs); Emit("newobj instance void class W<" + tme.ilty + ">::.ctor(!0)"); EmitWriteLine(); }
static string EmitLocal(TypeMapEntry tme) { return EmitLocal(tme, "V"); }
static string EmitLocal(TypeMapEntry tme) { return(EmitLocal(tme, "V")); }
public bool Generate(bool skipJniAddNativeMethodRegistrationAttributeScan, List <TypeDefinition> javaTypes, string outputDirectory, bool generateNativeAssembly, out ApplicationConfigTaskState appConfState) { if (String.IsNullOrEmpty(outputDirectory)) { throw new ArgumentException("must not be null or empty", nameof(outputDirectory)); } if (!Directory.Exists(outputDirectory)) { Directory.CreateDirectory(outputDirectory); } int assemblyId = 0; int maxJavaNameLength = 0; int maxModuleFileNameLength = 0; var knownAssemblies = new Dictionary <string, int> (StringComparer.Ordinal); var tempModules = new Dictionary <byte[], ModuleData> (); Dictionary <AssemblyDefinition, int> moduleCounter = null; var mvidCache = new Dictionary <Guid, byte[]> (); appConfState = new ApplicationConfigTaskState { JniAddNativeMethodRegistrationAttributePresent = skipJniAddNativeMethodRegistrationAttributeScan }; foreach (TypeDefinition td in javaTypes) { UpdateApplicationConfig(td, appConfState); string assemblyName = td.Module.Assembly.FullName; if (!knownAssemblies.ContainsKey(assemblyName)) { assemblyId++; knownAssemblies.Add(assemblyName, assemblyId); } // We must NOT use Guid here! The reason is that Guid sort order is different than its corresponding // byte array representation and on the runtime we need the latter in order to be able to binary search // through the module array. byte[] moduleUUID; if (!mvidCache.TryGetValue(td.Module.Mvid, out moduleUUID)) { moduleUUID = td.Module.Mvid.ToByteArray(); mvidCache.Add(td.Module.Mvid, moduleUUID); } ModuleData moduleData; if (!tempModules.TryGetValue(moduleUUID, out moduleData)) { if (moduleCounter == null) { moduleCounter = new Dictionary <AssemblyDefinition, int> (); } moduleData = new ModuleData { Mvid = td.Module.Mvid, MvidBytes = moduleUUID, Assembly = td.Module.Assembly, AssemblyName = td.Module.Assembly.Name.Name, TypesScratch = new Dictionary <string, TypeMapEntry> (StringComparer.Ordinal), DuplicateTypes = new Dictionary <uint, TypeMapEntry> (), }; tempModules.Add(moduleUUID, moduleData); if (!generateNativeAssembly) { int moduleNum; if (!moduleCounter.TryGetValue(moduleData.Assembly, out moduleNum)) { moduleNum = 0; moduleCounter [moduleData.Assembly] = 0; } else { moduleNum++; moduleCounter [moduleData.Assembly] = moduleNum; } string fileName = $"{moduleData.Assembly.Name.Name}.{moduleNum}.typemap"; moduleData.OutputFilePath = Path.Combine(outputDirectory, fileName); if (maxModuleFileNameLength < fileName.Length) { maxModuleFileNameLength = fileName.Length; } } } string javaName = Java.Interop.Tools.TypeNameMappings.JavaNativeTypeManager.ToJniName(td); var entry = new TypeMapEntry { JavaName = javaName, JavaNameLength = outputEncoding.GetByteCount(javaName), ManagedTypeName = td.FullName, Token = td.MetadataToken.ToUInt32(), AssemblyNameIndex = knownAssemblies [assemblyName] }; if (generateNativeAssembly) { if (entry.JavaNameLength > maxJavaNameLength) { maxJavaNameLength = entry.JavaNameLength; } } if (moduleData.TypesScratch.ContainsKey(entry.JavaName)) { // This is disabled because it costs a lot of time (around 150ms per standard XF Integration app // build) and has no value for the end user. The message is left here because it may be useful to us // in our devloop at some point. //logger ($"Warning: duplicate Java type name '{entry.JavaName}' in assembly '{moduleData.AssemblyName}' (new token: {entry.Token})."); moduleData.DuplicateTypes.Add(entry.Token, entry); } else { moduleData.TypesScratch.Add(entry.JavaName, entry); } } var modules = tempModules.Values.ToArray(); Array.Sort(modules, new ModuleUUIDArrayComparer()); var typeMapEntryComparer = new TypeMapEntryArrayComparer(); foreach (ModuleData module in modules) { if (module.TypesScratch.Count == 0) { module.Types = new TypeMapEntry[0]; continue; } module.Types = module.TypesScratch.Values.ToArray(); Array.Sort(module.Types, typeMapEntryComparer); } NativeTypeMappingData data; if (!generateNativeAssembly) { string typeMapIndexPath = Path.Combine(outputDirectory, "typemap.index"); using (var indexWriter = MemoryStreamPool.Shared.CreateBinaryWriter()) { OutputModules(modules, indexWriter, maxModuleFileNameLength + 1); indexWriter.Flush(); MonoAndroidHelper.CopyIfStreamChanged(indexWriter.BaseStream, typeMapIndexPath); } GeneratedBinaryTypeMaps.Add(typeMapIndexPath); data = new NativeTypeMappingData(logger, new ModuleData[0], 0); } else { data = new NativeTypeMappingData(logger, modules, maxJavaNameLength + 1); } NativeAssemblerTargetProvider asmTargetProvider; bool sharedBitsWritten = false; bool sharedIncludeUsesAbiPrefix; foreach (string abi in supportedAbis) { sharedIncludeUsesAbiPrefix = false; switch (abi.Trim()) { case "armeabi-v7a": asmTargetProvider = new ARMNativeAssemblerTargetProvider(is64Bit: false); sharedIncludeUsesAbiPrefix = true; // ARMv7a is "special", it uses different directive prefix // than the others and the "shared" code won't build for it break; case "arm64-v8a": asmTargetProvider = new ARMNativeAssemblerTargetProvider(is64Bit: true); break; case "x86": asmTargetProvider = new X86NativeAssemblerTargetProvider(is64Bit: false); break; case "x86_64": asmTargetProvider = new X86NativeAssemblerTargetProvider(is64Bit: true); break; default: throw new InvalidOperationException($"Unknown ABI {abi}"); } var generator = new TypeMappingNativeAssemblyGenerator(asmTargetProvider, data, Path.Combine(outputDirectory, "typemaps"), sharedBitsWritten, sharedIncludeUsesAbiPrefix); using (var sw = MemoryStreamPool.Shared.CreateStreamWriter(outputEncoding)) { generator.Write(sw); sw.Flush(); MonoAndroidHelper.CopyIfStreamChanged(sw.BaseStream, generator.MainSourceFile); if (!sharedIncludeUsesAbiPrefix) { sharedBitsWritten = true; } } } return(true); }
static string EmitLocal(TypeMapEntry tme, string prefix) { string varname = "'" + prefix + "_" + tme.ty + "'"; Emit(".locals(" + tme.ilty + " " + varname + ")"); return varname; }