public LayoutControlItem CreateGridListViewItem(ClassDesc subclass) { LayoutControlItem item = new LayoutControlItem(); BaseViewControl baseViewControl = new BaseViewControl(); baseViewControl.BindData(new DynamicObjectHelper(subclass)); baseViewControl.HideFilter(); baseViewControl.SimpleEditor(); item.Control = baseViewControl; item.TextVisible = false; item.SizeConstraintsType = SizeConstraintsType.Custom; item.ControlMinSize = new Size(0, 800); subclassviewList.Add(baseViewControl); return(item); }
public static string GetClass(string _assembly, string _namespace, string name, bool il2cpp) { GetAssembly(_assembly, il2cpp); var desc = new ClassDesc() { Assembly = _assembly, Namespace = _namespace, Name = name }; if (il2cpp) { I2ClassSet.Add(desc); } else { MonoClassSet.Add(desc); } return(GetClassDefine(desc, il2cpp)); }
static void EmitClass(TextWriter tw, ClassDesc clz) { string genericParamString = ""; if (clz.GenericParams != null) { genericParamString = $"<{clz.GenericParams}>"; } tw.WriteLine($".class {clz.ClassFlags} {clz.Name}{genericParamString}"); if (clz.BaseType != null) { tw.WriteLine($" extends {clz.BaseType}"); } if (clz.InterfacesImplemented != null) { bool first = true; foreach (string iface in clz.InterfacesImplemented) { if (first) { first = false; tw.Write(" implements "); } else { tw.Write("," + Environment.NewLine + " "); } tw.Write(iface); } if (first == true) { throw new Exception(); } tw.WriteLine(""); } tw.WriteLine("{"); }
private LayoutControlGroup CreateLayoutGroup(List <TableColumnDesc> column_list, List <TableColumnDisplay> display_list, List <TableColumnReference> reference_list, List <TableColumnRegular> rule_list) { string group_text = String.Empty; string sub_group_text = String.Empty; TableColumnDisplay display = display_list.Find(obj => obj.Id == column_list[0].Id); if (display != null) { group_text = display.Column_display_name; sub_group_text = display.Sub_group_display_name; } LayoutControlGroup grp = this.CreateLayoutGroup(sub_group_text == String.Empty?group_text:sub_group_text); foreach (TableColumnDesc col in column_list) { TableColumnDisplay column_display = display_list.Find(obj => obj.Id == col.Id); TableColumnReference column_reference = reference_list.Find(obj => obj.Id == col.Id); TableColumnRegular column_rule = rule_list.Find(obj => obj.Id == col.Id); string column_text = column_display != null?column_display.Column_display_name:col.Column_name; string column_ref_value = GlobeData.tableColumnDescList.Find(obj => obj.Column_idx == column_reference.Reference_value_column_id).Column_name; string column_ref_text = GlobeData.tableColumnDescList.Find(obj => obj.Column_idx == column_reference.Reference_text_column_id).Column_name; var ref_data = new object(); LayoutControlItem itm = new LayoutControlItem(); if (column_reference != null) { ClassDesc tmp = GlobeData.classDescList.Find(obj => obj.Id == column_reference.Reference_id); if (tmp != null) { object ref_class = GlobeData.assembly.CreateInstance(tmp.Class_name); ref_data = ref_class.GetType().InvokeMember("GetDataList", BindingFlags.Default | BindingFlags.InvokeMethod, null, ref_class, null); } } switch (col.Column_edit_type) { case ObjectEnum.ColumnEditType.Calc: itm = this.CreateCalcItem(column_text, col.Column_name, 10, 8, col.Is_readonly); break; case ObjectEnum.ColumnEditType.Check: itm = this.CreateCheckItem(column_text, col.Column_name, col.Is_readonly); break; case ObjectEnum.ColumnEditType.CheckedCombo: itm = this.CreateCheckedComboItem(column_text, col.Column_name, column_rule != null ? column_rule.ItemList.Split(',').ToList(): new List <String>(), "(Select All)", ',', col.Is_readonly); break; case ObjectEnum.ColumnEditType.Combo: itm = this.CreateComboItem(column_text, col.Column_name, ref_data, column_ref_text, column_ref_value, col.Is_readonly); break; case ObjectEnum.ColumnEditType.Date: itm = this.CreateDateItem(column_text, col.Column_name, col.Is_readonly); break; case ObjectEnum.ColumnEditType.Grid: break; case ObjectEnum.ColumnEditType.LookUp: itm = this.CreateSearchFindItem(column_text, col.Column_name, ref_data, column_ref_text, column_ref_value, col.Is_readonly); break; case ObjectEnum.ColumnEditType.Memo: itm = this.CreateMemoItem(column_text, col.Column_name, column_rule != null ? column_rule.Max_length : 65535, col.Is_readonly); break; case ObjectEnum.ColumnEditType.Spin: itm = this.CreateSpinItem(column_text, col.Column_name, column_rule != null ? column_rule.Max_value : int.MaxValue, column_rule != null ? column_rule.Min_value : int.MinValue, 1, false, col.Is_readonly); break; case ObjectEnum.ColumnEditType.Text: itm = this.CreateTextItem(column_text, col.Column_name, column_rule != null ? column_rule.Max_length : 65535, column_rule != null?column_rule.Mask_type:MaskType.None, column_rule != null?column_rule.Mask:String.Empty, col.Is_readonly); break; case ObjectEnum.ColumnEditType.Time: itm = this.CreateTimeItem(column_text, col.Column_name, col.Is_readonly); break; case ObjectEnum.ColumnEditType.Toggle: itm = this.CreateToggleSwitchItem(column_text, col.Column_name, column_rule != null ? column_rule.Toggle_off_value : false, column_rule != null ? column_rule.Toggle_on_value : true, column_rule != null ? column_rule.Toggle_off_text : "Off", column_rule != null ? column_rule.Toggle_on_text : "ON", col.Is_readonly); break; } grp.AddItem(itm); } return(grp); }
public void CreateLayoutEditor(DynamicObjectHelper dynamicObject) { if (dynamicObject.classDesc == null) { return; } this.dynamicObject = dynamicObject; bindingSource.DataSource = dynamicObject.objclass; int group_idx = 1; while (true) { List <TableColumnDesc> list = dynamicObject.ColumnList.FindAll(obj => obj.Group_idx == group_idx); if (list.Count > 0) { string group_text = String.Empty; TableColumnDisplay display = dynamicObject.ColumnLanguageDisplayList.Find(obj => obj.Id == list[0].Id); if (display != null) { group_text = display.Column_display_name; } LayoutControlGroup grp = this.CreateLayoutGroup(group_text); #region 子Group (int min, int max)tuple = (list.Min(obj => obj.Sub_group_idx), list.Min(obj => obj.Sub_group_idx)); if (tuple.min > 0) { for (int k = tuple.min; k <= tuple.max; k++) { List <TableColumnDesc> sub_list = list.FindAll(obj => obj.Sub_group_idx == k); grp.Add(this.CreateLayoutGroup(sub_list, dynamicObject.ColumnLanguageDisplayList, dynamicObject.ColumnReferenceList, dynamicObject.ColumnRegularList)); } } #endregion #region 单个Group else { grp = this.CreateLayoutGroup(list, dynamicObject.ColumnLanguageDisplayList, dynamicObject.ColumnReferenceList, dynamicObject.ColumnRegularList); } #endregion this.layoutEdit.AddGroup(grp); } else { break; } group_idx++; } List <ClassRelated> sub_class = GlobeData.classRelatedList.FindAll(obj => obj.Main_class_id == dynamicObject.classDesc.Id); foreach (ClassRelated sub in sub_class) { ClassDesc subclass = GlobeData.classDescList.Find(obj => obj.Id == sub.Sub_class_id); LayoutControlGroup grp1 = this.CreateLayoutGroup(subclass.Class_name); LayoutControlItem item = this.CreateGridListViewItem(subclass); grp1.AddItem(item); layoutEdit.AddGroup(grp1); } }
static void Main(string[] args) { using StreamWriter twOutputCommon = new StreamWriter(Path.Combine(args[0], @$ "{CommonAndImplAssemblyName}.il")); using StreamWriter twOutputTest = new StreamWriter(Path.Combine(args[0], @$ "{TestAssemblyName}.il")); StringWriter swMainMethodBody = new StringWriter(); StringWriter swTestClassMethods = new StringWriter(); EmitTestGlobalHeader(twOutputCommon); EmitAssemblyRecord(twOutputCommon, CommonAndImplAssemblyName); EmitCodeForCommonLibrary(twOutputCommon); GenerateImplementations(twOutputCommon); EmitTestGlobalHeader(twOutputTest); EmitAssemblyExternRecord(twOutputTest, CommonAndImplAssemblyName); EmitAssemblyRecord(twOutputTest, TestAssemblyName); foreach (var scenario in TestScenario.GetScenarios()) { string scenarioName = scenario.ToString(); string constrainedType = AppendSuffixToConstrainedType(scenario, GetConstrainedTypeName(scenario.ConstrainedTypeDefinition), out bool skipScenario); if (skipScenario) { continue; } string interfaceTypeSansImplPrefix; string interfaceMethod; string constrainedTypePrefix; if (constrainedType.Contains("Valuetype")) { constrainedTypePrefix = $"valuetype "; } else { constrainedTypePrefix = $"class "; } switch (scenario.InterfaceType) { case InterfaceType.NonGeneric: interfaceTypeSansImplPrefix = "IFaceNonGeneric"; break; case InterfaceType.GenericOverString: if (scenario.CallerScenario == CallerMethodScenario.GenericOverConstrainedType) { interfaceTypeSansImplPrefix = "IFaceGeneric`1<!!1>"; } else { interfaceTypeSansImplPrefix = "IFaceGeneric`1<string>"; } break; case InterfaceType.GenericOverObject: if (scenario.CallerScenario == CallerMethodScenario.GenericOverConstrainedType) { interfaceTypeSansImplPrefix = "IFaceGeneric`1<!!1>"; } else { interfaceTypeSansImplPrefix = "IFaceGeneric`1<object>"; } break; case InterfaceType.CuriouslyRecurringGeneric: interfaceTypeSansImplPrefix = $"IFaceCuriouslyRecurringGeneric`1<{constrainedTypePrefix}{constrainedType}>"; break; default: throw new Exception("Unexpected value"); } string interfaceMethodRoot; string interfaceMethodInstantiation = ""; switch (scenario.MethodType) { case MethodType.NormalMethod: interfaceMethodRoot = "NormalMethod"; break; case MethodType.GenericMethodOverInt: interfaceMethodRoot = "GenericMethod"; interfaceMethodInstantiation = "<int32>"; break; case MethodType.GenericMethodOverString: interfaceMethodRoot = "GenericMethod"; interfaceMethodInstantiation = "<string>"; break; case MethodType.GenericMethodOverTypeParameter: interfaceMethodRoot = "GenericMethod"; if (scenario.CallerScenario == CallerMethodScenario.NonGeneric) { continue; } interfaceMethodInstantiation = "<!!0>"; break; default: throw new Exception("Unexpected"); } interfaceMethod = interfaceMethodRoot + interfaceMethodInstantiation; TextWriter twIL; MethodDesc mdIndividualTestMethod = new MethodDesc(); string basicTestMethodName = $"Test_{scenarioName}"; mdIndividualTestMethod.Name = basicTestMethodName; mdIndividualTestMethod.HasBody = true; mdIndividualTestMethod.MethodFlags = "public static"; mdIndividualTestMethod.MethodImpls = null; mdIndividualTestMethod.ReturnType = "void"; mdIndividualTestMethod.Arguments = ""; string expectedString = constrainedTypePrefix + AppendSuffixToConstrainedType(scenario, GetConstrainedTypeName(scenario.ConstrainedTypeDefinition, withImplPrefix: false), out _) + "'" + interfaceTypeSansImplPrefix + "." + interfaceMethodRoot + "'" + interfaceMethodInstantiation; expectedString = expectedString.Replace(ImplPrefix, ""); if (scenario.CallerScenario == CallerMethodScenario.NonGeneric) { EmitTestMethod(); CallTestEntrypoint($" call void TestEntrypoint::{mdIndividualTestMethod.Name}()"); } else { string methodInstantiation; switch (scenario.CallerScenario) { case CallerMethodScenario.GenericOverInt32: case CallerMethodScenario.GenericOverString: mdIndividualTestMethod.Name = mdIndividualTestMethod.Name + "<T>"; methodInstantiation = "string"; if (scenario.CallerScenario == CallerMethodScenario.GenericOverInt32) { methodInstantiation = "int32"; } expectedString = expectedString.Replace("!!0", $"{methodInstantiation}"); expectedString = expectedString.Replace(ImplPrefix, ""); EmitTestMethod(); CallTestEntrypoint($" call void TestEntrypoint::{basicTestMethodName}<{methodInstantiation}>()"); break; case CallerMethodScenario.GenericOverConstrainedType: mdIndividualTestMethod.Name = $"{mdIndividualTestMethod.Name}<({(interfaceTypeSansImplPrefix.Contains("`") ? "class " : "")}{CommonPrefix}{interfaceTypeSansImplPrefix}) T,U>"; expectedString = expectedString.Replace("!!0", $"{constrainedTypePrefix}{constrainedType}"); expectedString = expectedString.Replace(ImplPrefix, ""); EmitTestMethod(); string callCommand = GetSetBangBang1IfNeeded("string") + $" call void TestEntrypoint::{basicTestMethodName}<{constrainedTypePrefix}{constrainedType},string>()"; if (scenario.InterfaceType == InterfaceType.GenericOverObject) { callCommand = callCommand + Environment.NewLine + GetSetBangBang1IfNeeded("object") + $" call void TestEntrypoint::{basicTestMethodName}<{constrainedTypePrefix}{constrainedType},object>()"; } CallTestEntrypoint(callCommand); string GetSetBangBang1IfNeeded(string bangBang1Expected) { if (expectedString.Contains("!!1")) { return($" ldstr \"{bangBang1Expected}\"" + Environment.NewLine + " stsfld string [GenericContextCommonCs]Statics::BangBang1Param" + Environment.NewLine); } else { return(""); } } break; default: throw new Exception("AACLL"); } } void CallTestEntrypoint(string callCommand) { swMainMethodBody.WriteLine(" .try {"); swMainMethodBody.WriteLine(callCommand); swMainMethodBody.WriteLine($" leave.s {scenarioName}Done"); swMainMethodBody.WriteLine(" } catch [System.Runtime]System.Exception {"); swMainMethodBody.WriteLine($" stloc.0"); swMainMethodBody.WriteLine($" ldstr \"{scenarioName}\""); swMainMethodBody.WriteLine($" ldstr \"{expectedString}\""); swMainMethodBody.WriteLine($" ldloc.0"); swMainMethodBody.WriteLine($" callvirt instance string [System.Runtime]System.Object::ToString()"); swMainMethodBody.WriteLine($" call void [GenericContextCommonCs]Statics::CheckForFailure(string,string,string)"); swMainMethodBody.WriteLine($" leave.s {scenarioName}Done"); swMainMethodBody.WriteLine(" }"); swMainMethodBody.WriteLine($"{scenarioName}Done: nop"); } // If test scenario requires generic class caller, Create Caller class and make a global method method which calls it // If test scenario requires generic method caller, create global generic method as required and non-generic test method // If test scenario requires non-generic method caller, just make global method as caller // Call callee // // Create Callee class // With callee method that implements scenario // fill expected value static with string computed based on scenario + exact type of calle class/generic args of callee method // compute expected result string void EmitTestMethod() { EmitMethod(swTestClassMethods, mdIndividualTestMethod); EmitILToCallActualMethod(swTestClassMethods); swTestClassMethods.WriteLine($" ldstr \"{scenario.ToString()}\""); swTestClassMethods.WriteLine($" ldstr \"{expectedString}\""); if (expectedString.Contains("!!1")) { swTestClassMethods.WriteLine(" ldstr \"!!1\""); swTestClassMethods.WriteLine(" ldsfld string [GenericContextCommonCs]Statics::BangBang1Param"); swTestClassMethods.WriteLine(" call instance string [System.Runtime]System.String::Replace(string, string)"); } swTestClassMethods.WriteLine($" call void {CommonCsPrefix}Statics::CheckForFailure(string,string)"); swTestClassMethods.WriteLine($" ret"); twIL = swTestClassMethods; EmitEndMethod(swTestClassMethods, mdIndividualTestMethod); } void EmitILToCallActualMethod(TextWriter twActualIL) { // Emit the IL to call the actual method switch (scenario.Operation) { case OperationTested.Call: EmitConstrainedPrefix(); twActualIL.WriteLine($" call void class {ImplPrefix}{interfaceTypeSansImplPrefix}::{interfaceMethod}()"); break; case OperationTested.Ldftn: EmitConstrainedPrefix(); twActualIL.WriteLine($" ldftn void class {ImplPrefix}{interfaceTypeSansImplPrefix}::{interfaceMethod}()"); twActualIL.WriteLine($" volatile."); twActualIL.WriteLine($" stsfld native int modreq([System.Runtime]System.Runtime.CompilerServices.IsVolatile) {CommonCsPrefix}Statics::FtnHolder"); twActualIL.WriteLine($" volatile."); twActualIL.WriteLine($" ldsfld native int modreq([System.Runtime]System.Runtime.CompilerServices.IsVolatile) {CommonCsPrefix}Statics::FtnHolder"); twActualIL.WriteLine($" calli void()"); break; case OperationTested.CreateDelegate: twActualIL.WriteLine(" ldnull"); EmitConstrainedPrefix(); twActualIL.WriteLine($" ldftn void class {ImplPrefix}{interfaceTypeSansImplPrefix}::{interfaceMethod}()"); twActualIL.WriteLine($" newobj instance void [System.Runtime]System.Action::.ctor(object,"); twActualIL.WriteLine($" native int)"); twActualIL.WriteLine($" volatile."); twActualIL.WriteLine($" stsfld class [System.Runtime] System.Action modreq([System.Runtime] System.Runtime.CompilerServices.IsVolatile) {CommonCsPrefix}Statics::ActionHolder"); twActualIL.WriteLine($" volatile."); twActualIL.WriteLine($" ldsfld class [System.Runtime] System.Action modreq([System.Runtime] System.Runtime.CompilerServices.IsVolatile) {CommonCsPrefix}Statics::ActionHolder"); twActualIL.WriteLine($" callvirt instance void[System.Runtime] System.Action::Invoke()"); break; default: throw new Exception(); } void EmitConstrainedPrefix() { if (scenario.CallerScenario == CallerMethodScenario.GenericOverConstrainedType) { twActualIL.WriteLine($" constrained. !!0"); } else { twActualIL.WriteLine($" constrained. {constrainedTypePrefix}{constrainedType}"); } } } } ClassDesc mainClass = new ClassDesc(); mainClass.BaseType = "[System.Runtime]System.Object"; mainClass.ClassFlags = "public auto ansi"; mainClass.Name = "TestEntrypoint"; EmitClass(twOutputTest, mainClass); twOutputTest.Write(swTestClassMethods.ToString()); MethodDesc mainMethod = new MethodDesc(); mainMethod.Name = "Main"; mainMethod.Arguments = ""; mainMethod.ReturnType = "int32"; mainMethod.MethodImpls = null; mainMethod.HasBody = true; mainMethod.MethodFlags = "public static"; EmitMethod(twOutputTest, mainMethod); twOutputTest.WriteLine(" .entrypoint"); twOutputTest.WriteLine(" .locals init (class [System.Runtime]System.Exception V_0)"); twOutputTest.Write(swMainMethodBody.ToString()); twOutputTest.WriteLine($" call int32 { CommonCsPrefix}Statics::ReportResults()"); twOutputTest.WriteLine(" ret"); EmitEndMethod(twOutputTest, mainMethod); EmitEndClass(twOutputTest, mainClass); }
static void GenerateImplementations(TextWriter tw) { foreach (var constrainedTypeDefinition in (ConstrainedTypeDefinition[])typeof(ConstrainedTypeDefinition).GetEnumValues()) { string baseType = constrainedTypeDefinition.ToString().Contains("Valuetype") ? "[System.Runtime]System.ValueType" : "[System.Runtime]System.Object"; ClassDesc implClass = new ClassDesc(); implClass.BaseType = baseType; implClass.Name = GetConstrainedTypeName(constrainedTypeDefinition, false); implClass.ClassFlags = "public auto ansi"; string implTypePrefix = "class"; if (constrainedTypeDefinition.ToString().Contains("Valuetype")) { implTypePrefix = "valuetype"; implClass.ClassFlags = implClass.ClassFlags + " sealed"; } if (constrainedTypeDefinition.ToString().StartsWith("Generic")) { implClass.GenericParams = "T"; } List <string> interfacesImplemented = new List <string>(); StringWriter implsGenerated = new StringWriter(); implClass.InterfacesImplemented = interfacesImplemented; if (constrainedTypeDefinition.ToString().StartsWith("Generic")) { GenerateImpl(implClass.Name + "<!0>", "IFaceNonGeneric", "", false); GenerateImpl(implClass.Name + "<!0>", "IFaceGeneric`1", "<string>", true); GenerateImpl(implClass.Name + "<!0>", "IFaceGeneric`1", "<object>", true); GenerateImpl(implClass.Name + "<!0>", $"IFaceCuriouslyRecurringGeneric`1", $"<{implTypePrefix} {implClass.Name}<!0>>", true); } else { GenerateImpl(implClass.Name, "IFaceNonGeneric", "", false); GenerateImpl(implClass.Name, "IFaceGeneric`1", "<string>", true); GenerateImpl(implClass.Name, "IFaceGeneric`1", "<object>", true); GenerateImpl(implClass.Name, $"IFaceCuriouslyRecurringGeneric`1", $"<{implTypePrefix} {implClass.Name}>", true); } EmitClass(tw, implClass); if (!constrainedTypeDefinition.ToString().Contains("Valuetype")) { tw.WriteLine($" .method public hidebysig specialname rtspecialname "); tw.WriteLine($" instance void .ctor() cil managed"); tw.WriteLine($" {{"); tw.WriteLine($" .maxstack 8"); tw.WriteLine($" IL_0000: ldarg.0"); tw.WriteLine($" IL_0001: call instance void {implClass.BaseType}::.ctor()"); tw.WriteLine($" IL_0006: ret"); tw.WriteLine($" }}"); } tw.WriteLine(implsGenerated.ToString()); EmitEndClass(tw, implClass); void GenerateImpl(string implType, string iface, string ifaceGenericArguments, bool isGeneric) { interfacesImplemented.Add(ToILDasmTypeName(iface, ifaceGenericArguments)); MethodDesc implMethodDesc = new MethodDesc(); implMethodDesc.Name = $"'{iface}{ifaceGenericArguments}.NormalMethod'"; implMethodDesc.MethodFlags = "public static"; implMethodDesc.ReturnType = "void"; implMethodDesc.HasBody = true; implMethodDesc.MethodImpls = new string[] { $"method void {ToILDasmTypeName(ImplPrefix+iface, ifaceGenericArguments)}::NormalMethod()" }; EmitMethod(implsGenerated, implMethodDesc); GenerateMethodBody(false); EmitEndMethod(implsGenerated, implMethodDesc); implMethodDesc.Name = $"'{iface}{ifaceGenericArguments}.GenericMethod'<U>"; implMethodDesc.MethodImpls = new string[] { $"method void {ToILDasmTypeName(ImplPrefix + iface, ifaceGenericArguments)}::GenericMethod<[1]>()" }; EmitMethod(implsGenerated, implMethodDesc); GenerateMethodBody(true); EmitEndMethod(implsGenerated, implMethodDesc); void GenerateMethodBody(bool genericMethod) { implsGenerated.WriteLine($" ldtoken {implTypePrefix} {implType}"); implsGenerated.WriteLine($" call string {CommonCsPrefix}Statics::MakeName(valuetype [System.Runtime]System.RuntimeTypeHandle)"); string methodNameToEmit = implMethodDesc.Name; if (methodNameToEmit.EndsWith("<U>")) { methodNameToEmit = methodNameToEmit.Substring(0, methodNameToEmit.Length - 3); } implsGenerated.WriteLine($" ldstr \"{methodNameToEmit}\""); if (methodNameToEmit.Contains("!!0")) { implsGenerated.WriteLine($" ldstr \"!!0\""); implsGenerated.WriteLine($" ldtoken !!0"); implsGenerated.WriteLine($" call string {CommonCsPrefix}Statics::MakeName(valuetype[System.Runtime]System.RuntimeTypeHandle)"); implsGenerated.WriteLine($" call instance string [System.Runtime]System.String::Replace(string, string)"); } if (methodNameToEmit.Contains("!!1")) { implsGenerated.WriteLine($" ldstr \"!!1\""); implsGenerated.WriteLine($" ldtoken !!1"); implsGenerated.WriteLine($" call string {CommonCsPrefix}Statics::MakeName(valuetype[System.Runtime]System.RuntimeTypeHandle)"); implsGenerated.WriteLine($" call instance string [System.Runtime]System.String::Replace(string, string)"); } if (methodNameToEmit.Contains("!0")) { implsGenerated.WriteLine($" ldstr \"!0\""); implsGenerated.WriteLine($" ldtoken !0"); implsGenerated.WriteLine($" call string {CommonCsPrefix}Statics::MakeName(valuetype[System.Runtime]System.RuntimeTypeHandle)"); implsGenerated.WriteLine($" call instance string [System.Runtime]System.String::Replace(string, string)"); } if (genericMethod) { implsGenerated.WriteLine($" ldstr \"<\""); implsGenerated.WriteLine($" ldtoken !!0"); implsGenerated.WriteLine($" call string {CommonCsPrefix}Statics::MakeName(valuetype[System.Runtime]System.RuntimeTypeHandle)"); implsGenerated.WriteLine($" ldstr \">\""); implsGenerated.WriteLine($" call string[System.Runtime] System.String::Concat(string, string, string,string)"); } implsGenerated.WriteLine($" call string[System.Runtime] System.String::Concat(string, string)"); implsGenerated.WriteLine($" stsfld string {CommonCsPrefix}Statics::String"); implsGenerated.WriteLine($" ret"); } } } }
static void EmitEndClass(TextWriter tw, ClassDesc clz) { tw.WriteLine($"}} // end of class {clz.Name}"); }
private static string GetClassDefine(ClassDesc klass, bool il2cpp) { var perfix = il2cpp ? "il2cpp" : "mono"; return($"{perfix}_get_class_{klass.Namespace}_{klass.Name}()".Replace(".", "_")); }
public void Resolve(string assemblyName, string dllName) { // create assembly and module AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( new AssemblyName(assemblyName), AssemblyBuilderAccess.Save ); ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName, dllName); // create Inanity.Object type TypeBuilder inanityObjectTypeBuilder = moduleBuilder.DefineType( "Inanity.Object", TypeAttributes.Public | TypeAttributes.Abstract, null, // parent new Type[] { typeof(IDisposable) } ); inanityObjectTypeBuilder.DefineField( "ptr", typeof(UIntPtr), FieldAttributes.Family ); ConstructorBuilder inanityObjectConstructorBuilder = inanityObjectTypeBuilder.DefineDefaultConstructor(MethodAttributes.Family); { MethodBuilder disposeMethod = inanityObjectTypeBuilder.DefineMethod( "Dispose", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.HideBySig, typeof(void), new Type[] { } ); disposeMethod.SetImplementationFlags(MethodImplAttributes.InternalCall); } inanityObjectTypeBuilder.CreateType(); // create type bulders for all classes foreach (string fullClassName in classes.Keys) { classes[fullClassName].typeBuilder = moduleBuilder.DefineType( fullClassName, TypeAttributes.Public | (classes[fullClassName].constructor == null ? TypeAttributes.Abstract : 0) ); } // lambda for resolving types Func <string, Type> resolveType = delegate(string typeName) { switch (typeName) { case "void": return(typeof(void)); case "bool": return(typeof(bool)); case "int32": return(typeof(Int32)); case "uint32": return(typeof(UInt32)); case "int64": return(typeof(Int64)); case "uint64": return(typeof(UInt64)); case "float": return(typeof(float)); case "double": return(typeof(double)); case "string": return(typeof(string)); case "object": return(typeof(object)); default: { ClassDesc classDesc; if (!classes.TryGetValue(typeName, out classDesc)) { throw new Exception("Cannot resolve type " + typeName); } return(classDesc.typeBuilder); } } }; // set parents, create constructors and methods foreach (string className in classes.Keys) { ClassDesc classDesc = classes[className]; TypeBuilder typeBuilder = classDesc.typeBuilder; // set parent { TypeBuilder parentTypeBuilder; if (classDesc.parentClassName != null) { if (!classes.TryGetValue(classDesc.parentClassName, out classDesc.parentClassDesc)) { throw new Exception("Parent class " + classDesc.parentClassName + " is not registered"); } parentTypeBuilder = classDesc.parentClassDesc.typeBuilder; } else { parentTypeBuilder = inanityObjectTypeBuilder; } typeBuilder.SetParent(parentTypeBuilder); } // set constructor { ConstructorDesc constructorDesc = classDesc.constructor; if (constructorDesc != null) { Type[] argumentTypes = constructorDesc.argumentTypes.Select(resolveType).ToArray(); // define extern thunk method MethodBuilder methodBuilder = typeBuilder.DefineMethod( "__c", MethodAttributes.Private, CallingConventions.HasThis, typeof(void), argumentTypes ); methodBuilder.SetImplementationFlags(MethodImplAttributes.InternalCall); classDesc.constructorThunkMethodBuilder = methodBuilder; // define constructor ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor( MethodAttributes.Public, CallingConventions.HasThis, argumentTypes ); classDesc.constructorBuilder = constructorBuilder; } else { classDesc.constructorBuilder = typeBuilder.DefineDefaultConstructor(MethodAttributes.Family); } } // add methods foreach (string methodName in classDesc.methods.Keys) { MethodDesc methodDesc = classDesc.methods[methodName]; MethodBuilder methodBuilder = typeBuilder.DefineMethod( methodName, MethodAttributes.Public | MethodAttributes.Final, CallingConventions.HasThis, resolveType(methodDesc.returnType), methodDesc.argumentTypes.Select(resolveType).ToArray() ); methodBuilder.SetImplementationFlags(MethodImplAttributes.InternalCall); } // add static methods foreach (string staticMethodName in classDesc.staticMethods.Keys) { FunctionDesc functionDesc = classDesc.staticMethods[staticMethodName]; MethodBuilder methodBuilder = typeBuilder.DefineMethod( staticMethodName, MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.Static, CallingConventions.Standard, resolveType(functionDesc.returnType), functionDesc.argumentTypes.Select(resolveType).ToArray() ); methodBuilder.SetImplementationFlags(MethodImplAttributes.InternalCall); } } // emit code for constructors foreach (ClassDesc classDesc in classes.Values) { ConstructorDesc constructorDesc = classDesc.constructor; if (constructorDesc == null) { continue; } Type[] argumentTypes = constructorDesc.argumentTypes.Select(resolveType).ToArray(); ILGenerator ilGenerator = classDesc.constructorBuilder.GetILGenerator(); ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Call, classDesc.parentClassDesc != null ? classDesc.parentClassDesc.constructorBuilder : inanityObjectConstructorBuilder ); ilGenerator.Emit(OpCodes.Ldarg_0); for (int i = 0; i < argumentTypes.Length; ++i) { ilGenerator.Emit(OpCodes.Ldarg, i + 1); } ilGenerator.Emit(OpCodes.Call, classDesc.constructorThunkMethodBuilder); ilGenerator.Emit(OpCodes.Ret); } // create types foreach (ClassDesc classDesc in classes.Values) { classDesc.typeBuilder.CreateType(); } // save assembly assemblyBuilder.Save(dllName); }
static void Main(string[] args) { int maxCases = Int32.MaxValue; string rootPath = Path.GetDirectoryName(typeof(Program).Assembly.Location); string scenarioSuffix = ""; if (args.Length > 0) { rootPath = args[0]; } if (args.Length > 2) { maxCases = Int32.Parse(args[1]); scenarioSuffix = args[2]; } using StreamWriter twOutputTest = new StreamWriter(Path.Combine(rootPath, @$ "{TestAssemblyName}{scenarioSuffix}.il")); StringWriter swMainMethodBody = new StringWriter(); StringWriter swTestClassMethods = new StringWriter(); EmitTestGlobalHeader(twOutputTest); EmitAssemblyRecord(twOutputTest, TestAssemblyName); int currentCase = 0; foreach (var scenario in TestScenario.GetScenarios()) { if ((++currentCase) > maxCases) { break; } string scenarioName = scenario.ToString(); // Emit interface ClassDesc iface = new ClassDesc(); iface.ClassFlags = "interface public abstract auto ansi"; iface.GenericParams = scenario.InterfaceTypeGenericParams; iface.Name = "Interface" + scenarioName + GenericTypeSuffix(scenario.InterfaceTypeGenericParams);; EmitClass(twOutputTest, iface); MethodDesc ifaceMethod = new MethodDesc(); ifaceMethod.HasBody = false; ifaceMethod.MethodFlags = "public newslot virtual abstract static"; ifaceMethod.ReturnType = scenario.InterfaceReturnType; ifaceMethod.Name = "Method"; EmitMethod(twOutputTest, ifaceMethod); EmitEndMethod(twOutputTest, ifaceMethod); EmitEndClass(twOutputTest, iface); // Emit base class which implements static method to implement interface. Mark it abstract if we don't put the methodimpl there ClassDesc baseType = new ClassDesc(); baseType.BaseType = "[System.Runtime]System.Object"; switch (scenario.InterfaceImplementationApproach) { case InterfaceImplementationApproach.OnBaseType: case InterfaceImplementationApproach.OnBothBaseAndDerived: baseType.ClassFlags = "public auto ansi"; break; case InterfaceImplementationApproach.OnBothBaseAndDerivedBaseIsAbstract: baseType.ClassFlags = "public abstract auto ansi"; break; default: throw new Exception("Unknown interface approach"); } baseType.GenericParams = scenario.BaseTypeGenericParams; baseType.Name = "Base" + scenarioName + GenericTypeSuffix(scenario.BaseTypeGenericParams); if (scenario.InterfaceImplementationApproach.ToString().Contains("Base")) { baseType.InterfacesImplemented = new string[] { ToILDasmTypeName(iface.Name, scenario.InterfaceTypeInstantiationOnBaseType) }; } EmitClass(twOutputTest, baseType); switch (scenario.InterfaceImplementationApproach) { case InterfaceImplementationApproach.OnBaseType: case InterfaceImplementationApproach.OnBothBaseAndDerived: MethodDesc ifaceImplMethod = new MethodDesc(); ifaceImplMethod.HasBody = true; ifaceImplMethod.MethodFlags = "public static"; ifaceImplMethod.ReturnType = scenario.BaseTypeReturnType; ifaceImplMethod.Name = "Method"; EmitMethod(twOutputTest, ifaceImplMethod); twOutputTest.WriteLine($" .override method {scenario.InterfaceReturnType} {ToILDasmTypeName(iface.Name, scenario.InterfaceTypeInstantiationOnBaseType)}::Method()"); twOutputTest.WriteLine($" .locals init ({scenario.BaseTypeReturnType} V_O)"); twOutputTest.WriteLine($" ldloca.s 0"); twOutputTest.WriteLine($" initobj {scenario.BaseTypeReturnType}"); twOutputTest.WriteLine($" ldloc.0"); twOutputTest.WriteLine($" ret"); EmitEndMethod(twOutputTest, ifaceImplMethod); break; case InterfaceImplementationApproach.OnBothBaseAndDerivedBaseIsAbstract: break; default: throw new Exception("Unknown interface approach"); } EmitEndClass(twOutputTest, baseType); // Emit derived class. ClassDesc derivedType = new ClassDesc(); derivedType.BaseType = ToILDasmTypeName(baseType.Name, scenario.BaseTypeInstantiationOnDerivedType); switch (scenario.InterfaceImplementationApproach) { case InterfaceImplementationApproach.OnBaseType: case InterfaceImplementationApproach.OnBothBaseAndDerived: case InterfaceImplementationApproach.OnBothBaseAndDerivedBaseIsAbstract: derivedType.ClassFlags = "public auto ansi"; break; default: throw new Exception("Unknown interface approach"); } derivedType.Name = "Derived" + scenarioName + GenericTypeSuffix(scenario.DerivedTypeGenericParams); derivedType.GenericParams = scenario.DerivedTypeGenericParams; if (scenario.InterfaceImplementationApproach.ToString().Contains("Derived")) { derivedType.InterfacesImplemented = new string[] { ToILDasmTypeName(iface.Name, scenario.InterfaceTypeInstantiationOnDerivedType) }; } EmitClass(twOutputTest, derivedType); switch (scenario.InterfaceImplementationApproach) { case InterfaceImplementationApproach.OnBaseType: case InterfaceImplementationApproach.OnBothBaseAndDerived: break; case InterfaceImplementationApproach.OnBothBaseAndDerivedBaseIsAbstract: MethodDesc ifaceImplMethod = new MethodDesc(); ifaceImplMethod.HasBody = true; ifaceImplMethod.MethodFlags = "public static"; ifaceImplMethod.ReturnType = scenario.DerivedTypeReturnType; ifaceImplMethod.Name = "MethodImplOnDerived"; EmitMethod(twOutputTest, ifaceImplMethod); twOutputTest.WriteLine($" .override method {scenario.InterfaceReturnType} {ToILDasmTypeName(iface.Name, scenario.InterfaceTypeInstantiationOnDerivedType)}::Method()"); twOutputTest.WriteLine($" .locals init ({scenario.DerivedTypeReturnType} V_O)"); twOutputTest.WriteLine($" ldloca.s 0"); twOutputTest.WriteLine($" initobj {scenario.DerivedTypeReturnType}"); twOutputTest.WriteLine($" ldloc.0"); twOutputTest.WriteLine($" ret"); EmitEndMethod(twOutputTest, ifaceImplMethod); break; default: throw new Exception("Unknown interface approach"); } EmitEndClass(twOutputTest, derivedType); // Emit test method which performs constrained call to hit the method MethodDesc mdIndividualTestMethod = new MethodDesc(); string basicTestMethodName = $"Test_{scenarioName}"; mdIndividualTestMethod.Name = basicTestMethodName; mdIndividualTestMethod.HasBody = true; mdIndividualTestMethod.MethodFlags = "public static"; mdIndividualTestMethod.MethodImpls = null; mdIndividualTestMethod.ReturnType = "void"; mdIndividualTestMethod.Arguments = ""; EmitMethod(swTestClassMethods, mdIndividualTestMethod); swTestClassMethods.WriteLine($" constrained. {ToILDasmTypeName(derivedType.Name, scenario.DerivedTypeInstantiation)}"); swTestClassMethods.WriteLine($" call {scenario.CallReturnType} {ToILDasmTypeName(iface.Name, scenario.CallInterfaceTypeInstantiation)}::Method()"); if (scenario.CallReturnType != "void") { // TODO: should we rather convert the value to string and stsfld Statics.String? swTestClassMethods.WriteLine($" pop"); } swTestClassMethods.WriteLine($" ldstr \"{scenarioName}\""); swTestClassMethods.WriteLine($" ldnull"); swTestClassMethods.WriteLine($" call void {CommonCsPrefix}Statics::CheckForFailure(string,string)"); swTestClassMethods.WriteLine($" ret"); EmitEndMethod(swTestClassMethods, mdIndividualTestMethod); // Call test method from main method swMainMethodBody.WriteLine(" .try {"); swMainMethodBody.WriteLine($" call void TestEntrypoint::{mdIndividualTestMethod.Name}()"); swMainMethodBody.WriteLine($" leave.s {scenarioName}Done"); swMainMethodBody.WriteLine(" } catch [System.Runtime]System.Exception {"); swMainMethodBody.WriteLine($" stloc.0"); swMainMethodBody.WriteLine($" ldstr \"{scenarioName}\""); swMainMethodBody.WriteLine($" ldnull"); swMainMethodBody.WriteLine($" ldloc.0"); swMainMethodBody.WriteLine($" callvirt instance string [System.Runtime]System.Object::ToString()"); swMainMethodBody.WriteLine($" call void [TypeHierarchyCommonCs]Statics::CheckForFailure(string,string,string)"); swMainMethodBody.WriteLine($" leave.s {scenarioName}Done"); swMainMethodBody.WriteLine(" }"); swMainMethodBody.WriteLine($"{scenarioName}Done: nop"); string GenericTypeSuffix(string genericParams) { if (String.IsNullOrEmpty(genericParams)) { return(""); } return($"`{genericParams.Split(',').Length}"); } } ClassDesc mainClass = new ClassDesc(); mainClass.BaseType = "[System.Runtime]System.Object"; mainClass.ClassFlags = "public auto ansi"; mainClass.Name = "TestEntrypoint"; EmitClass(twOutputTest, mainClass); twOutputTest.Write(swTestClassMethods.ToString()); MethodDesc mainMethod = new MethodDesc(); mainMethod.Name = "Main"; mainMethod.Arguments = ""; mainMethod.ReturnType = "int32"; mainMethod.MethodImpls = null; mainMethod.HasBody = true; mainMethod.MethodFlags = "public static"; EmitMethod(twOutputTest, mainMethod); twOutputTest.WriteLine(" .entrypoint"); twOutputTest.WriteLine(" .locals init (class [System.Runtime]System.Exception V_0)"); twOutputTest.Write(swMainMethodBody.ToString()); twOutputTest.WriteLine($" call int32 { CommonCsPrefix}Statics::ReportResults()"); twOutputTest.WriteLine(" ret"); EmitEndMethod(twOutputTest, mainMethod); EmitEndClass(twOutputTest, mainClass); }
public ArrayValueConverter(ClassDesc desc) { this.desc = desc; }
public ClassValueConverter(ClassDesc desc) { this.desc = desc; }