Beispiel #1
0
        //
        // 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);
        }
Beispiel #2
0
        //
        // 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);
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
                        }
                    }
                }
Beispiel #5
0
        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);
            }
        }