// // create a dummy method that is used to extract information // about this generic type: the number of type arguments // it takes, and the data class type. this is used by the // CreateGeneric method in the system.RuntimeType constructor. // public static void CreateGenericInfoMethod(JavaClass theClass, JavaClass dataClass, CilType fromType) { int numGeneric = fromType.GenericParameters.Count; var parameters = new List <JavaFieldRef>(numGeneric); for (int i = 0; i < numGeneric; i++) { parameters.Add(new JavaFieldRef("", SystemGenericType)); } var(returnType, maxStack) = (dataClass == null) ? (JavaType.VoidType, 0) : (new JavaType(0, 0, dataClass.Name), 1); var methodRef = new JavaMethodRef("-generic-info-method", returnType, parameters); var code = CilMain.CreateHelperMethod(theClass, methodRef, numGeneric, maxStack); code.Method.Flags |= JavaAccessFlags.ACC_STATIC | JavaAccessFlags.ACC_FINAL | JavaAccessFlags.ACC_SYNTHETIC; if (dataClass != null) { code.NewInstruction(0x01 /* aconst_null */, null, null); } code.NewInstruction(returnType.ReturnOpcode, null, null); }
// // create the IGenericObject methods // public static void BuildGetTypeMethod(JavaClass theClass, CilType theType) { theClass.AddInterface("system.IGenericObject"); var methodRef = new JavaMethodRef("system-IGenericObject-GetType", CilType.SystemTypeType); var code = CilMain.CreateHelperMethod(theClass, methodRef, 1, 1); if (theType.HasGenericParameters) { // this is a proper generic type with a -generic-type field // created by MakeGenericClass, which also invoked us. code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(0xB4 /* getfield */, theType, ConcreteTypeField); code.NewInstruction(JavaType.ObjectType.ReturnOpcode, null, null); } else { // this is a non-generic type, but has a generic base type // which implements the GetType method, so we want to provide // an overriding implementation that returns the correct type. // we are invoked by TypeBuilder. code.StackMap = new JavaStackMap(); LoadMaybeGeneric(theType, code); code.NewInstruction(JavaType.ObjectType.ReturnOpcode, null, null); } }
public static void CreateToStringMethod(JavaClass theClass) { // we add an explicit ToString method if it is missing in a // non-interface class, which derives directly from java.lang.Object if ((theClass.Flags & JavaAccessFlags.ACC_INTERFACE) != 0) { return; } if (!theClass.Super.Equals(JavaType.ObjectType.ClassName)) { return; } foreach (var m in theClass.Methods) { if (m.Name == "toString" && (m.Flags & JavaAccessFlags.ACC_STATIC) == 0 && m.ReturnType.Equals(JavaType.StringType) && m.Parameters.Count == 0) { return; } } // create method: string ToString() => GetType().ToString(); var toStringMethod = new JavaMethodRef("toString", JavaType.StringType); var code = CilMain.CreateHelperMethod(theClass, toStringMethod, 1, 1); code.Method.Flags &= ~JavaAccessFlags.ACC_BRIDGE; code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(0xB8 /* invokestatic */, new JavaType(0, 0, "system.Object"), new JavaMethodRef("GetType", CilType.SystemTypeType, JavaType.ObjectType)); code.NewInstruction(0xB6 /* invokevirtual */, JavaType.ObjectType, toStringMethod); code.NewInstruction(JavaType.StringType.ReturnOpcode, null, null); }
static void CreateValueMethods(JavaClass valueClass, CilType fromType, int numCastableInterfaces) { CreateValueClearMethod(valueClass, fromType); CreateValueCopyToMethod(valueClass, fromType); CreateValueCloneMethod(valueClass, fromType, numCastableInterfaces); // // system-ValueMethod-Clear() resets all fields to their default value // void CreateValueClearMethod(JavaClass valueClass, CilType fromType) { var code = CilMain.CreateHelperMethod(valueClass, CilMethod.ValueClear, 1, 2); if (valueClass.Fields != null && valueClass.Fields.Count != 0) { foreach (var fld in valueClass.Fields) { if ((fld.Flags & JavaAccessFlags.ACC_STATIC) != 0) { continue; } if (fld.Type is CilType fldType && fldType.IsValueClass) { code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(0xB4 /* getfield */, fromType, fld); code.NewInstruction(0xB6 /* invokevirtual */, fldType, CilMethod.ValueClear); } else { code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(fld.Type.InitOpcode, null, null); code.NewInstruction(0xB5 /* putfield */, fromType, fld); } } }
public static List <JavaClass> BuildProxyMethods(List <CilInterface> allInterfaces, TypeDefinition fromType, CilType intoType, JavaClass theClass) { // // process only if the class (or interface) has any methods or super interfaces // var classMethods = theClass.Methods; if (classMethods.Count == 0) { return(null); } bool isInterface = intoType.IsInterface; if ((!isInterface) && theClass.Interfaces == null) { return(null); } var theMethods = CilInterfaceMethod.CollectAll(fromType); // // if any interfaces are marked [RetainName], make sure that // all corresponding methods are also marked [RetainName] // CheckRetainNameMethods(theMethods, allInterfaces, intoType); // // if this is an abstract class but forced to an interface via [AddInterface] // decoration, then we need to remove all constructors generated for the class // if (intoType.IsInterface) { if (!fromType.IsInterface) { for (int i = classMethods.Count; i-- > 0;) { if (classMethods[i].Name == "<init>") { classMethods.RemoveAt(i); } } } if (intoType.HasGenericParameters) { // the RuntimeType constructor in baselib uses IGenericEntity // marker interface to identify generic classes. note that // real generic types implement IGenericObject -> IGenericEntity. theClass.AddInterface("system.IGenericEntity"); } return(null); } // // for each implemented interface, build proxy methods // List <JavaClass> output = null; int ifcNumber = 0; foreach (var ifc in allInterfaces) { if ((!ifc.DirectReference) && ifc.SuperImplements) { // we don't have to build proxy for an interface if it is // implemented by a super type and not by our primary type continue; } if (ifc.GenericTypes == null) { foreach (var ifcMethod in ifc.Methods) { // build proxy methods: interface$method -> method var newMethod = BuildPlainProxy(ifcMethod, intoType, theMethods); if (newMethod != null) { newMethod.Class = theClass; theClass.Methods.Add(newMethod); } } } else { var ifcClass = CreateInnerClass(theClass, intoType, ++ifcNumber); ifcClass.AddInterface(ifc.InterfaceType.JavaName); if (output == null) { output = new List <JavaClass>(); CreateInterfaceArrayField(theClass); } output.Add(ifcClass); // if the class implements a generic interface for multiple types, // then we need a method suffix to differentiate between the methods. // see also: CilMethod::InsertMethodNamePrefix string methodSuffix = ""; foreach (var genericType in ifc.GenericTypes) { methodSuffix += "--" + CilMethod.GenericParameterSuffixName(genericType); } foreach (var ifcMethod in ifc.Methods) { // build proxy classes: proxy sub-class -> this class BuildGenericProxy(ifcMethod, methodSuffix, intoType, theMethods, ifcClass); } } } return(output); JavaClass CreateInnerClass(JavaClass parentClass, CilType parentType, int ifcNumber) { // generic interfaces are implemented as proxy sub-classes which // call methods on the parent class object. we need to define // an inner class. this class has one instance field which is a // reference to the parent class. the constructor takes this // reference as a parameter and initializes the instance field. var newClass = CilMain.CreateInnerClass(parentClass, parentClass.Name + "$$generic" + ifcNumber.ToString()); var fld = new JavaField(); fld.Name = ParentFieldName; fld.Type = parentType; fld.Class = newClass; fld.Flags = JavaAccessFlags.ACC_PRIVATE; newClass.Fields.Add(fld); var code = CilMain.CreateHelperMethod(newClass, new JavaMethodRef("<init>", JavaType.VoidType, JavaType.ObjectType), 2, 2); code.Method.Flags &= ~JavaAccessFlags.ACC_BRIDGE; // invalid for constructor code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(0xB7 /* invokespecial */, JavaType.ObjectType, new JavaMethodRef("<init>", JavaType.VoidType)); code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(0x19 /* aload */, null, (int)1); code.NewInstruction(0xC0 /* checkcast */, parentType, null); code.NewInstruction(0xB5 /* putfield */, new JavaType(0, 0, newClass.Name), new JavaFieldRef(ParentFieldName, parentType)); code.NewInstruction(JavaType.VoidType.ReturnOpcode, null, null); return(newClass); } void CreateInterfaceArrayField(JavaClass parentClass) { // the parent class has a helper array field that is used to track // the proxy objects generated for implemented generic interfaces. // see also: InitInterfaceArrayField, below. var fld = new JavaField(); fld.Name = InterfaceArrayField.Name; fld.Type = InterfaceArrayField.Type; fld.Class = parentClass; fld.Flags = JavaAccessFlags.ACC_PRIVATE; if (parentClass.Fields == null) { parentClass.Fields = new List <JavaField>(1); } parentClass.Fields.Add(fld); } }