コード例 #1
0
ファイル: ValueUtil.cs プロジェクト: spaceflint7/bluebonnet
        //
        // create default parameterless constructor.  (it will be called at the
        // top of any method which allocates a value type local.)  and note that
        // if this is a generic value type, this new constructor will be further
        // modified in GenericUtil.MakeGenericClass.FixConstructorsInFrom
        //

        static void CreateDefaultConstructor(JavaClass valueClass, CilType fromType,
                                             int numCastableInterfaces, bool initFields)
        {
            foreach (var oldMethod in valueClass.Methods)
            {
                if (oldMethod.Name == "<init>")
                {
                    return;
                }
            }

            var code = CilMethod.CreateConstructor(valueClass, fromType.GenericParametersCount, true);

            if (fromType.HasGenericParameters)
            {
                code.StackMap = new JavaStackMap();
                var genericMark = CilMain.GenericStack.Mark();
                CilMain.GenericStack.EnterMethod(fromType, code.Method, true);

                // initialize the generic type field
                GenericUtil.InitializeTypeField(fromType, code);

                CilMain.GenericStack.Release(genericMark);
                code.MaxStack = code.StackMap.GetMaxStackSize(CilMain.Where);
            }

            // init the array of generic interfaces
            InterfaceBuilder.InitInterfaceArrayField(
                fromType, numCastableInterfaces, code, 0);

            if (initFields)
            {
                var oldLabel = code.SetLabel(0xFFFF);

                InitializeInstanceFields(valueClass, fromType, null, code);

                code.SetLabel(oldLabel);
            }

            code.NewInstruction(0x19 /* aload */, null, (int)0);
            code.NewInstruction(0xB7 /* invokespecial */, new JavaType(0, 0, valueClass.Super),
                                new JavaMethodRef("<init>", JavaType.VoidType));

            code.MaxStack = code.StackMap.GetMaxStackSize(CilMain.Where);
            if (code.MaxStack < 1)
            {
                code.MaxStack = 1;
            }

            code.NewInstruction(JavaType.VoidType.ReturnOpcode, null, null);
        }
コード例 #2
0
ファイル: GenericUtil.cs プロジェクト: spaceflint7/bluebonnet
        public static JavaClass MakeGenericClass(JavaClass fromClass, CilType fromType)
        {
            // if the generic class has static fields or a static initializer
            // then we need to move those into a separate class that can be
            // instantiated multiple times for multiple separate instances,
            // one for each concrete implementation of the generic type.

            int numGeneric = fromType.GenericParameters.Count;

            var dataClass = MoveStaticFields(fromClass, null);

            dataClass = MoveStaticInit(fromClass, dataClass);

            if (dataClass != null)
            {
                FixConstructorInData(dataClass, numGeneric);
            }

            // a generic class implements the IGenericObject interface,
            // and has a generic-type field for the concrete implementation
            // of the generic type and generic arguments

            CreateGenericTypeFields(fromClass, numGeneric);
            BuildGetTypeMethod(fromClass, fromType);

            return(dataClass);

            //
            // move any static fields from the generic class,
            // as instance fields in a new class
            //

            JavaClass MoveStaticFields(JavaClass fromClass, JavaClass dataClass)
            {
                var fields = fromClass.Fields;

                if (fields == null)
                {
                    return(dataClass);
                }

                int n = fields.Count;

                for (int i = 0; i < n;)
                {
                    var fld = fields[i];
                    if ((fld.Flags & JavaAccessFlags.ACC_STATIC) == 0)
                    {
                        i++;
                        continue;
                    }
                    if (((CilType)fld.Type).IsLiteral)
                    {
                        i++;
                        continue;
                    }

                    if (dataClass == null)
                    {
                        dataClass = CreateClass(fromClass);
                    }

                    if (fld.Constant != null)
                    {
                        throw CilMain.Where.Exception($"initializer in static field '{fld.Name}' in generic class");
                    }

                    fields.RemoveAt(i);
                    n--;

                    fld.Flags &= ~JavaAccessFlags.ACC_STATIC;
                    dataClass.Fields.Add(fld);
                }

                return(dataClass);
            }

            //
            // move the static constructor/initializer
            // from the generic class to the new data class
            //

            JavaClass MoveStaticInit(JavaClass fromClass, JavaClass dataClass)
            {
                var methods = fromClass.Methods;
                int n       = methods.Count;

                for (int i = 0; i < n;)
                {
                    var mth = methods[i];
                    if (mth.Name != "<clinit>")
                    {
                        i++;
                        continue;
                    }

                    if (dataClass == null)
                    {
                        dataClass = CreateClass(fromClass);
                    }

                    methods.RemoveAt(i);
                    n--;

                    mth.Name  = "<init>";
                    mth.Class = dataClass;
                    mth.Flags = JavaAccessFlags.ACC_PUBLIC;
                    dataClass.Methods.Add(mth);
                }

                return(dataClass);
            }

            //
            // create a constructor if there was no static initializer,
            // or inject a call to super class constructor
            //

            void FixConstructorInData(JavaClass dataClass, int numGeneric)
            {
                JavaCode code;
                bool     insertReturn;

                if (dataClass.Methods.Count == 0)
                {
                    code         = CilMethod.CreateConstructor(dataClass, numGeneric, true);
                    insertReturn = true;

                    code.MaxStack  = 1;
                    code.MaxLocals = 1 + numGeneric;
                }
                else
                {
                    code = dataClass.Methods[0].Code;
                    if (code.MaxStack < 1)
                    {
                        code.MaxStack = 1;
                    }

                    // we are injecting a call to super constructor at the very top,
                    // so local 0 should have the proper type, not uninitializedThis
                    code.StackMap.SetLocalInAllFrames(
                        0, CilType.From(new JavaType(0, 0, dataClass.Name)), null);

                    insertReturn = false;
                }

                code.Instructions.Insert(0, new Instruction(
                                             0x19 /* aload */, null, (int)0, 0xFFFF));

                code.Instructions.Insert(1, new Instruction(
                                             0xB7 /* invokespecial */, JavaType.ObjectType,
                                             new JavaMethodRef("<init>", JavaType.VoidType), 0xFFFF));

                // the static initializer can call static methods on its own type,
                // and those methods can invoke system.RuntimeType.GetType() to get
                // a reference to the generic type that is still being initialized.
                // and more importantly, a reference to the the static-generic data
                // object that is constructed by this method.  to make the object
                // available to such access, we call system.RuntimeType.SetStatic().
                // see also system.RuntimeType.MakeGenericType/MakeGenericType().

                code.Instructions.Insert(2, new Instruction(
                                             0x19 /* aload */, null, (int)0, 0xFFFF));

                code.Instructions.Insert(3, new Instruction(
                                             0xB8 /* invokestatic */, CilType.SystemRuntimeTypeType,
                                             new JavaMethodRef("SetStatic",
                                                               JavaType.VoidType, JavaType.ObjectType), 0xFFFF));

                if (insertReturn)
                {
                    code.NewInstruction(JavaType.VoidType.ReturnOpcode, null, null, 0xFFFF);
                }
            }

            //
            // create the new data class
            //

            JavaClass CreateClass(JavaClass fromClass) =>
            CilMain.CreateInnerClass(fromClass, fromClass.Name + "$$static", 0,
                                     markGenericEntity: true);

            //
            // create a private instance field to hold the runtime type
            // for a particular combination of generic type and arguments
            //

            void CreateGenericTypeFields(JavaClass fromClass, int numGeneric)
            {
                var fld = new JavaField();

                fld.Name  = ConcreteTypeField.Name;
                fld.Type  = ConcreteTypeField.Type;
                fld.Class = fromClass;
                fld.Flags = JavaAccessFlags.ACC_PRIVATE;

                if (fromClass.Fields == null)
                {
                    fromClass.Fields = new List <JavaField>();
                }

                fromClass.Fields.Add(fld);
            }
        }