Exemple #1
0
        public void Translate(Mono.Cecil.Cil.Instruction inst)
        {
            switch (inst.OpCode.Code)
            {
            case Code.Throw:
            case Code.Rethrow:  Translate_Throw(inst);      break;

            case Code.Leave:
            case Code.Leave_S:  Translate_Leave(inst);      break;

            case Code.Endfinally:            Translate_Endfinally(inst.Offset); break;

            case Code.Endfilter:                    Translate_Endfilter(inst);  return;

            default:                                throw new InvalidProgramException();
            }

            //
            // these instructions break the normal flow of execution and clear the
            // stack frame.  if the following instruction already has a stack frame,
            // due to some earlier forward jump, we load that frame
            //

            CilMain.LoadFrameOrClearStack(stackMap, inst);

            locals.TrackUnconditionalBranch(inst);
        }
Exemple #2
0
        static string ImportName(TypeReference fromType, int numGeneric)
        {
            string name = CilMain.MakeValidTypeName(fromType.Name);

            if (fromType.IsNested)
            {
                var parent = CilType.From(fromType.DeclaringType);
                name = parent.ClassName + "$" + name;
            }
            else if (!string.IsNullOrEmpty(fromType.Namespace))
            {
                name = CilMain.MakeValidTypeName(fromType.Namespace.ToLowerInvariant())
                       + "." + name;
            }

            if (numGeneric != 0)
            {
                // the apostrophe character may get replaced in MakeValidTypeName(),
                // so we look for it in the original name string
                int index = fromType.Name.IndexOf('`');
                if (index != -1)
                {
                    index = index - fromType.Name.Length + name.Length;
                    name  = name.Substring(0, index) + "$$" + numGeneric;
                }
            }

            return(name);
        }
        //
        // 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);
            }
        }
Exemple #4
0
        static int ConvertToLong(JavaCode code, TypeCode oldType, TypeCode newType)
        {
            if (oldType == TypeCode.Int64 || oldType == TypeCode.UInt64)
            {
                return(0x00); // nop
            }
            if (oldType == TypeCode.Double)
            {
                return(0x8F); // d2l
            }
            if (oldType == TypeCode.Single)
            {
                return(0x8C); // f2l
            }
            if (newType == TypeCode.UInt64)
            {
                code.NewInstruction(0x85 /* i2l */, null, null);
                code.StackMap.PushStack(JavaType.LongType);
                long maskValue = (oldType == TypeCode.Byte)   ? 0xFF
                               : (oldType == TypeCode.UInt16) ? 0xFFFF
                                                              : 0xFFFFFFFF;
                code.NewInstruction(0x12 /* ldc */, null, (long)maskValue);
                code.StackMap.PushStack(JavaType.LongType);
                code.StackMap.PopStack(CilMain.Where);
                code.StackMap.PopStack(CilMain.Where);
                return(0x7F); // land
            }

            CilMain.MakeRoomForCategory2ValueOnStack(code);
            return(0x85); // i2l
        }
        //
        // 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);
        }
Exemple #6
0
        static byte TestBool(JavaCode code, JavaType stackTop)
        {
            if (stackTop.IsReference)
            {
                return(0xC7); // ifnonnull
            }

            if (stackTop.PrimitiveType == TypeCode.Int64 ||
                stackTop.PrimitiveType == TypeCode.UInt64 ||
                stackTop.PrimitiveType == TypeCode.Int32 ||
                stackTop.PrimitiveType == TypeCode.UInt32 ||
                stackTop.PrimitiveType == TypeCode.Int16 ||
                stackTop.PrimitiveType == TypeCode.UInt16 ||
                stackTop.PrimitiveType == TypeCode.SByte ||
                stackTop.PrimitiveType == TypeCode.Byte ||
                stackTop.PrimitiveType == TypeCode.Char ||
                stackTop.PrimitiveType == TypeCode.Boolean)
            {
                if (stackTop.PrimitiveType == TypeCode.Int64 ||
                    stackTop.PrimitiveType == TypeCode.UInt64)
                {
                    CilMain.MakeRoomForCategory2ValueOnStack(code, JavaType.LongType);
                    code.NewInstruction(0x09 /* lconst_0 (long) */, null, null);
                    code.NewInstruction(0x94 /* lcmp (long) */, null, null);
                }

                return(0x9A); // ifne != zero
            }

            throw new InvalidProgramException();
        }
Exemple #7
0
        void LoadStoreField(Code op, object data)
        {
            bool ok = false;

            if (data is FieldReference fieldRef)
            {
                var fldName  = CilMain.MakeValidMemberName(fieldRef.Name);
                var fldClass = CilMain.GenericStack.EnterType(fieldRef.DeclaringType);
                var fldType  = ValueUtil.GetBoxedFieldType(fldClass, fieldRef);

                if (fldClass.Equals(JavaType.StringType) ||
                    fldClass.Equals(JavaType.ThrowableType))
                {
                    // generally we translate System.String to java.lang.String,
                    // and System.Exception to java.lang.Throwable,
                    // but not in the case of a field reference
                    fldClass = CilType.From(new JavaType(0, 0, fldClass.JavaName));
                }

                bool isLoad     = (op != Code.Stfld && op != Code.Stsfld);
                bool isStatic   = (op == Code.Ldsfld || op == Code.Ldsflda || op == Code.Stsfld);
                bool isAddress  = (op == Code.Ldflda || op == Code.Ldsflda);
                bool isVolatile = CheckVolatile(fldType);

                if (isLoad)
                {
                    if (isAddress)
                    {
                        ok = LoadFieldAddress(fldName, fldType, fldClass, isStatic);
                    }
                    else
                    {
                        ok = LoadFieldValue(fldName, fldType, fldClass, isStatic, isVolatile);
                    }
                }
                else
                {
                    ok = StoreFieldValue(fldName, fldType, fldClass, isStatic, isVolatile);
                }
            }

            if (!ok)
            {
                throw new InvalidProgramException();
            }
        }
Exemple #8
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);
        }
Exemple #9
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);
                        }
                    }
                }
Exemple #10
0
        public static JavaClass FixClass(JavaClass fromClass, CilType fromType)
        {
            JavaType  interfaceType  = InterfaceType(fromType);
            JavaClass interfaceClass = null;

            var fromMethods = fromClass.Methods;

            for (int i = fromMethods.Count; i-- > 0;)
            {
                var nm = fromMethods[i].Name;
                if (nm == "BeginInvoke" || nm == "EndInvoke")
                {
                    fromClass.Methods.RemoveAt(i);
                }
            }

            foreach (var method in fromMethods)
            {
                if ((method.Flags & JavaAccessFlags.ACC_STATIC) == 0 && method.Code == null)
                {
                    if (method.Name == "<init>")
                    {
                        GenerateConstructor(method, fromType);
                    }
                    else if (method.Name == "Invoke")
                    {
                        if (interfaceClass != null)
                        {
                            break;
                        }

                        interfaceClass = MakeInterface(fromClass, method, interfaceType.ClassName);
                        GenerateInvoke(method, fromType, interfaceType);
                    }

                    /*else if (method.Name == "BeginInvoke")
                     * {
                     *  if (interfaceClass == null)
                     *      break;
                     *
                     *  GenerateBeginInvoke();
                     *  continue;
                     * }
                     * else if (method.Name == "EndInvoke")
                     * {
                     *  GenerateEndInvoke();
                     *  continue;
                     * }*/
                    else
                    {
                        break;
                    }

                    method.Flags &= ~JavaAccessFlags.ACC_ABSTRACT;
                }
            }

            if (interfaceClass == null)
            {
                throw CilMain.Where.Exception("invalid delegate class");
            }

            return(interfaceClass);

            //
            //
            //

            JavaClass MakeInterface(JavaClass fromClass, JavaMethod fromMethod, string newName)
            {
                var newClass = CilMain.CreateInnerClass(fromClass, newName,
                                                        JavaAccessFlags.ACC_PUBLIC
                                                        | JavaAccessFlags.ACC_ABSTRACT
                                                        | JavaAccessFlags.ACC_INTERFACE);

                var newMethod = new JavaMethod(newClass, fromMethod);

                newMethod.Flags = JavaAccessFlags.ACC_PUBLIC
                                  | JavaAccessFlags.ACC_ABSTRACT;
                if (IsPrimitive(newMethod.ReturnType))
                {
                    // primitive return value is translated to java.lang.Object,
                    // because the delegate target may return a generic type that
                    // is specialized for the primitive type in the delegate.
                    // see also GenerateInvoke and LoadFunction
                    newMethod.ReturnType = JavaType.ObjectType;
                }
                newClass.Methods.Add(newMethod);

                return(newClass);
            }

            //
            //
            //

            void GenerateConstructor(JavaMethod method, CilType dlgType)
            {
                var code = method.Code = new JavaCode();

                code.Method       = method;
                code.Instructions = new List <Instruction>();

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

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

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

                code.NewInstruction(0x19 /* aload_0 */, null, (int)0);
                code.NewInstruction(0x19 /* aload_1 */, null, (int)1);
                code.NewInstruction(0x19 /* aload_2 */, null, (int)2);

                code.NewInstruction(0xB7 /* invokespecial */,
                                    new JavaType(0, 0, method.Class.Super),
                                    new JavaMethodRef("<init>", JavaType.VoidType,
                                                      JavaType.ObjectType, JavaType.ObjectType));

                code.NewInstruction(0xB1 /* return (void) */, null, null);

                if (code.MaxStack < 3)
                {
                    code.MaxStack = 3;
                }
                code.MaxLocals = 3 + dlgType.GenericParametersCount;
            }

            //
            //
            //

            void GenerateInvoke(JavaMethod method, CilType dlgType, JavaType ifcType)
            {
                var delegateType = new JavaType(0, 0, "system.Delegate");

                var code = method.Code = new JavaCode();

                code.Method       = method;
                code.Instructions = new List <Instruction>();
                code.StackMap     = new JavaStackMap();

                code.StackMap.SetLocal(0, dlgType);
                int index = 1;

                for (int i = 0; i < method.Parameters.Count; i++)
                {
                    var paramType = (CilType)method.Parameters[i].Type;
                    code.StackMap.SetLocal(index, paramType);
                    index += paramType.Category;
                }
                code.StackMap.SaveFrame((ushort)0, false, CilMain.Where);

                //
                // step 1, call the target method through the interface reference
                // stored in the 'invokable' field of the system.Delegate class
                //

                code.NewInstruction(0x19 /* aload_0 */, null, (int)0);
                code.NewInstruction(0xB4 /* getfield */, delegateType,
                                    new JavaFieldRef("invokable", JavaType.ObjectType));

                code.NewInstruction(0xC0 /* checkcast */, ifcType, null);
                code.StackMap.PushStack(JavaType.ObjectType);

                // push method parameters 'invokeinterface'

                index = 1;
                for (int i = 0; i < method.Parameters.Count; i++)
                {
                    var paramType = (CilType)method.Parameters[i].Type;
                    code.NewInstruction(paramType.LoadOpcode, null, index);
                    code.StackMap.PushStack(paramType);

                    if (paramType.IsGenericParameter && (!paramType.IsByReference))
                    {
                        // invoke the helper method which identifies our boxed
                        // primitives and re-boxes them as java boxed values.
                        // see also: GenericType::DelegateParameterin baselib.
                        GenericUtil.LoadMaybeGeneric(
                            paramType.GetMethodGenericParameter(), code);
                        code.NewInstruction(0xB8 /* invokestatic */,
                                            SystemDelegateUtilType, DelegateParameterMethod);
                        code.StackMap.PopStack(CilMain.Where);
                    }
                    index += paramType.Category;
                }

                var returnType = (CilType)method.ReturnType;

                if (IsPrimitive(returnType))
                {
                    // primitive return value is translated to java.lang.Object,
                    // because the delegate target may return a generic type that
                    // is specialized for the primitive type in the delegate.
                    // see also GenerateInvoke and LoadFunction
                    var adjustedMethod = new JavaMethodRef(
                        method.Name, JavaType.ObjectType, method.Parameters);
                    code.NewInstruction(0xB9 /* invokeinterface */, ifcType, adjustedMethod);
                }
                else
                {
                    code.NewInstruction(0xB9 /* invokeinterface */, ifcType, method);
                }

                code.StackMap.ClearStack();
                code.StackMap.PushStack(returnType);

                // check if this delegate has a 'following' delegate,
                // attached via system.MulticastDelegate.CombineImpl

                code.NewInstruction(0x19 /* aload_0 */, null, (int)0);
                code.NewInstruction(0xB4 /* getfield */, delegateType,
                                    new JavaFieldRef("following", delegateType));
                code.NewInstruction(0xC7 /* ifnonnull */, null, (ushort)1);

                if (returnType.IsGenericParameter && (!returnType.IsByReference))
                {
                    GenericUtil.LoadMaybeGeneric(
                        returnType.GetMethodGenericParameter(), code);
                    code.NewInstruction(0xB8 /* invokestatic */,
                                        SystemDelegateUtilType, DelegateReturnValueMethod);
                    code.StackMap.PopStack(CilMain.Where);
                }
                else if (IsPrimitive(returnType))
                {
                    // if the delegate returns a primitive type, we need to unbox
                    // the object returned by the method we just called.  it will be
                    // a java boxed primitive (e.g. java.lang.Integer) if the called
                    // method actually returns a primitive, due to the boxing done
                    // by the invokedynamic mechanism.  if the called method returns
                    // a generic type, it will be our boxed type, e.g. system.Int32.
                    //
                    // see also DelegateReturnValueX helper methods in baselib,
                    // and MakeInterface and LoadFunction in this file.
                    var helperMethod = new JavaMethodRef(
                        DelegateReturnValueMethod.Name + returnType.ToDescriptor(),
                        returnType, JavaType.ObjectType);
                    code.NewInstruction(0xB8 /* invokestatic */,
                                        SystemDelegateUtilType, helperMethod);
                }

                code.NewInstruction(returnType.ReturnOpcode, null, index);
                code.StackMap.PopStack(CilMain.Where);

                //
                // step 2
                //
                // if this delegate has a 'following' delegate, then we need to
                // call it, but first get rid of the return value on the stack
                //

                byte popOpcode;

                if (returnType.Equals(JavaType.VoidType))
                {
                    popOpcode = 0x00; // nop
                }
                else // select 0x57 pop, or 0x58 pop2
                {
                    var adjustedReturnType =
                        IsPrimitive(returnType) ? JavaType.ObjectType : returnType;
                    code.StackMap.PushStack(adjustedReturnType);
                    popOpcode = (byte)(0x56 + returnType.Category);
                }
                code.NewInstruction(popOpcode, null, null, (ushort)1);
                code.StackMap.SaveFrame((ushort)1, true, CilMain.Where);

                // now call the Invoke method on the 'following' delegate

                code.NewInstruction(0x19 /* aload_0 */, null, (int)0);
                code.NewInstruction(0xB4 /* getfield */, delegateType,
                                    new JavaFieldRef("following", delegateType));
                code.NewInstruction(0xC0 /* checkcast */, dlgType, null);

                // push all method parameters for 'invokevirtual'

                index = 1;
                for (int i = 0; i < method.Parameters.Count; i++)
                {
                    var paramType = (CilType)method.Parameters[i].Type;
                    code.NewInstruction(paramType.LoadOpcode, null, index);

                    if (paramType.IsGenericParameter && (!paramType.IsByReference))
                    {
                        // invoke the helper method which identifies our boxed
                        // primitives and re-boxes them as java boxed values.
                        // see also: GenericType::DelegateParameterin baselib.
                        GenericUtil.LoadMaybeGeneric(
                            paramType.GetMethodGenericParameter(), code);
                        code.NewInstruction(0xB8 /* invokestatic */,
                                            SystemDelegateUtilType, DelegateParameterMethod);
                    }
                    index += paramType.Category;
                }

                code.NewInstruction(0xB6 /* invokevirtual */, dlgType, method);

                code.NewInstruction(returnType.ReturnOpcode, null, index);
                code.StackMap.ClearStack();

                code.MaxStack  = code.StackMap.GetMaxStackSize(CilMain.Where);
                code.MaxLocals = index;
            }

            //
            //
            //

            /*void GenerateBeginInvoke()
             * {
             * }*/

            //
            //
            //

            /*void GenerateEndInvoke()
             * {
             * }*/
        }
Exemple #11
0
        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);
            }
        }
Exemple #12
0
        static int ConvertToFloat(JavaCode code, TypeCode oldType, TypeCode newType, bool unsigned)
        {
            if (newType == TypeCode.Single)
            {
                //
                // convert to float
                //

                if (oldType == TypeCode.Single)
                {
                    return(0x00); // nop
                }
                if (oldType == TypeCode.Double)
                {
                    return(0x90); // d2f
                }
                if (oldType == TypeCode.Int64)
                {
                    return(0x89); // l2f
                }
                if (oldType != TypeCode.UInt64)
                {
                    return(0x86); // i2f
                }
                CallUnsignedLongToDouble(code);
                code.NewInstruction(0x8D /* d2f */, null, null);
                return(-1); // no output
            }

            else if (!unsigned)
            {
                //
                // convert to double
                //

                if (oldType == TypeCode.Double)
                {
                    return(0x00); // nop
                }
                if (oldType == TypeCode.Single)
                {
                    CilMain.MakeRoomForCategory2ValueOnStack(code);
                    return(0x8D); // f2d
                }

                if (oldType == TypeCode.Int64)
                {
                    return(0x8A); // l2d
                }
                if (oldType != TypeCode.UInt64)
                {
                    return(0x87); // i2d
                }
                CallUnsignedLongToDouble(code);
                return(-1); // no output
            }

            else
            {
                //
                // convert integer, interpreted as unsigned, to a double
                //

                if (oldType == TypeCode.Single || oldType == TypeCode.Double)
                {
                    throw new InvalidProgramException();
                }

                bool fromInt32 = (oldType != TypeCode.Int64 && oldType != TypeCode.UInt64);
                if (fromInt32)
                {
                    CilMain.MakeRoomForCategory2ValueOnStack(code);

                    code.NewInstruction(0x85 /* i2l */, null, null);
                    code.StackMap.PushStack(JavaType.LongType);

                    if (oldType == TypeCode.UInt32)
                    {
                        code.NewInstruction(0x12 /* ldc */, null, (long)0xFFFFFFFF);
                        code.StackMap.PushStack(JavaType.LongType);
                        code.NewInstruction(0x7F /* land */, null, null);
                        code.StackMap.PopStack(CilMain.Where);
                    }
                }

                CallUnsignedLongToDouble(code);

                if (fromInt32)
                {
                    code.StackMap.PopStack(CilMain.Where);
                }

                return(-1); // no output
            }

            void CallUnsignedLongToDouble(JavaCode code)
            {
                code.NewInstruction(0xB8 /* invokestatic */,
                                    CilType.From(JavaType.DoubleType).AsWritableClass,
                                    new JavaMethodRef("UnsignedLongToDouble",
                                                      JavaType.DoubleType, JavaType.LongType));
            }
        }
Exemple #13
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);
            }
        }
Exemple #14
0
        internal static void BuildJavaClass(TypeDefinition cilType, JavaClass parentClass)
        {
            CilMain.Where.Push($"class '{cilType.FullName}'");

            var genericMark = CilMain.GenericStack.Mark();
            var myType      = CilMain.GenericStack.EnterType(cilType);

            var jclass = new JavaClass();

            jclass.Name  = myType.JavaName;
            jclass.Flags = AttributesToAccessFlags(cilType.Attributes, myType.IsInterface);

            if (myType.IsInterface)
            {
                jclass.Super = JavaType.ObjectType.ClassName; // java.lang.Object
            }
            else if (cilType.BaseType != null)
            {
                var myBaseType = CilType.From(cilType.BaseType);
                jclass.Super = myBaseType.Equals(JavaType.ObjectType)
                             ? JavaType.ObjectType.ClassName // java.lang.Object
                             : myBaseType.JavaName;
            }
            else
            {
                throw CilMain.Where.Exception("missing base class");
            }

            var myInterfaces = ImportInterfaces(jclass, myType, cilType);

            int numCastableInterfaces = myType.IsGenericThisOrSuper
                                      ? InterfaceBuilder.CastableInterfaceCount(myInterfaces)
                                      : 0;

            ImportFields(jclass, cilType, myType.IsRetainName);

            ImportMethods(jclass, cilType, numCastableInterfaces);

            if (myType.JavaName == "system.Convert")
            {
                DiscardBase64MethodsInConvertClass(jclass);
            }

            ValueUtil.InitializeStaticFields(jclass, myType);

            if (myType.IsValueClass)
            {
                ValueUtil.MakeValueClass(jclass, myType, numCastableInterfaces);
            }

            else if (myType.IsEnum)
            {
                ValueUtil.MakeEnumClass(jclass, myType,
                                        cilType.HasCustomAttribute("System.FlagsAttribute", true));
            }

            else if (myType.IsDelegate)
            {
                var delegateInterface = Delegate.FixClass(jclass, myType);
                CilMain.JavaClasses.Add(delegateInterface);
            }

            // if derives directly from object, and does not implement ToString
            CodeBuilder.CreateToStringMethod(jclass);

            ResetFieldReferences(jclass);

            LinkClasses(jclass, parentClass, cilType);

            var interfaceClasses = InterfaceBuilder.BuildProxyMethods(
                myInterfaces, cilType, myType, jclass);

            if (interfaceClasses != null)
            {
                foreach (var childClass in interfaceClasses)
                {
                    CilMain.JavaClasses.Add(childClass);
                }
            }

            if (myType.HasGenericParameters)
            {
                JavaClass dataClass;

                if (!myType.IsInterface)
                {
                    dataClass = GenericUtil.MakeGenericClass(jclass, myType);
                    if (dataClass != null)
                    {
                        CilMain.JavaClasses.Add(dataClass);
                    }
                }
                else
                {
                    dataClass = null;
                }

                JavaClass infoClass = jclass;
                if (myType.IsInterface)
                {
                    // Android 'D8' desugars static methods on an interface by
                    // moving into a separate class, so we do it ourselves.
                    // see also system.RuntimeType.CreateGeneric() in baselib
                    infoClass = CilMain.CreateInnerClass(jclass, jclass.Name + "$$info");
                    CilMain.JavaClasses.Add(infoClass);
                }

                GenericUtil.CreateGenericInfoMethod(infoClass, dataClass, myType);

                GenericUtil.CreateGenericVarianceField(infoClass, myType, cilType);
            }

            if (myType.IsGenericThisOrSuper)
            {
                jclass.Signature = GenericUtil.MakeGenericSignature(cilType, jclass.Super);

                if (!myInterfaces.Exists(x => x.InterfaceType.JavaName == "system.IGenericObject"))
                {
                    if (!myType.IsInterface)
                    {
                        // create IGenericObject methods GetType and TryCast
                        // only if class did not already implement IGenericObject
                        if (!myType.HasGenericParameters)
                        {
                            GenericUtil.BuildGetTypeMethod(jclass, myType);
                        }

                        InterfaceBuilder.BuildTryCastMethod(
                            myInterfaces, myType, numCastableInterfaces, jclass);
                    }
                }
            }

            CilMain.GenericStack.Release(genericMark);
            CilMain.Where.Pop();
        }
Exemple #15
0
        public static void ImportMethods(JavaClass jclass, TypeDefinition cilType,
                                         int numCastableInterfaces)
        {
            if (cilType.HasMethods)
            {
                int n = cilType.Methods.Count;
                if (n > 0)
                {
                    jclass.Methods = new List <JavaMethod>(n);
                    for (int i = 0; i < n; i++)
                    {
                        var defMethod = cilType.Methods[i];

                        /*
                         * if (defMethod.HasCustomAttribute("Discard"))
                         *  continue; // if decorated with [java.attr.Discard], don't export to java
                         */

                        var genericMark = CilMain.GenericStack.Mark();
                        var myMethod    = CilMain.GenericStack.EnterMethod(defMethod);

                        var newMethod = new JavaMethod(jclass, myMethod.WithGenericParameters);
                        newMethod.Flags = AttributesToAccessFlags(
                            defMethod.Attributes, defMethod.HasOverrides,
                            (cilType.HasNestedTypes || cilType.HasGenericParameters));

                        if (myMethod.IsStatic & myMethod.IsConstructor)
                        {
                            newMethod.Flags &= ~(JavaAccessFlags.ACC_PUBLIC
                                                 | JavaAccessFlags.ACC_PRIVATE
                                                 | JavaAccessFlags.ACC_PROTECTED);
                        }

                        if (defMethod.HasBody)
                        {
                            CilMain.Where.Push($"method '{defMethod.Name}'");
                            CodeBuilder.BuildJavaCode(newMethod, myMethod, defMethod,
                                                      numCastableInterfaces);

                            if ((defMethod.ImplAttributes & MethodImplAttributes.Synchronized) != 0)
                            {
                                // if method is decorated with [MethodImplOptions.Synchronized],
                                // create a wrapper method that locks appropriately
                                jclass.Methods.Add(
                                    CodeBuilder.CreateSyncWrapper(newMethod, myMethod.DeclType));
                            }
                            else if (defMethod.Name == "Finalize" &&
                                     (!defMethod.HasParameters) && defMethod.IsVirtual)
                            {
                                // if method is a finalizer, create a wrapper method that
                                // checks if finalization was suppressed for the object

                                CodeBuilder.CreateSuppressibleFinalize(
                                    newMethod, myMethod.DeclType, jclass);
                            }

                            if (defMethod.IsVirtual)
                            {
                                InterfaceBuilder.BuildOverloadProxy(
                                    cilType, defMethod, myMethod, jclass);
                            }
                            else if (!myMethod.IsConstructor)
                            {
                                newMethod.Flags |= JavaAccessFlags.ACC_FINAL;
                            }

                            CilMain.Where.Pop();
                        }
                        else
                        {
                            if ((!defMethod.IsAbstract) &&
                                (defMethod.IsInternalCall || defMethod.IsPInvokeImpl))
                            {
                                // skip native methods
                                continue;
                            }

                            // clear ACC_STATIC and access, set ACC_ABSTRACT and ACC_PUBLIC
                            newMethod.Flags = (newMethod.Flags | JavaAccessFlags.ACC_ABSTRACT
                                               | JavaAccessFlags.ACC_PUBLIC)
                                              & ~(JavaAccessFlags.ACC_STATIC
                                                  | JavaAccessFlags.ACC_PRIVATE
                                                  | JavaAccessFlags.ACC_PROTECTED);
                        }

                        jclass.Methods.Add(newMethod);

                        CilMain.GenericStack.Release(genericMark);

                        if (myMethod.IsConstructor)
                        {
                            var dummyClass = CreateDummyClassForConstructor(myMethod, jclass);
                            if (dummyClass != null)
                            {
                                CilMain.JavaClasses.Add(dummyClass);
                            }
                        }
                        else if (myMethod.WithGenericParameters != myMethod &&
                                 (!myMethod.IsRetainName))
                        {
                            jclass.Methods.Add(
                                Delegate.CreateCapturingBridgeMethod(
                                    newMethod, myMethod.Parameters, cilType.IsInterface));
                        }
                    }
                }
            }
            else
            {
                jclass.Methods = new List <JavaMethod>(0);
            }

            JavaClass CreateDummyClassForConstructor(CilMethod theMethod, JavaClass theClass)
            {
                if (!theMethod.HasDummyClassArg)
                {
                    return(null);
                }
                return(CilMain.CreateInnerClass(
                           theClass,
                           theMethod.Parameters[
                               theMethod.Parameters.Count - 1].Type.ClassName));
            }
        }
Exemple #16
0
        public static void ImportFields(JavaClass jclass, TypeDefinition cilType, bool isRetainName)
        {
            if (cilType.HasFields)
            {
                int n = cilType.Fields.Count;
                if (n > 0)
                {
                    if (isRetainName)
                    {
                        throw CilMain.Where.Exception("fields not supported in a [RetainName] type");
                    }

                    jclass.Fields = new List <JavaField>(n);
                    for (int i = 0; i < n; i++)
                    {
                        var cilField = cilType.Fields[i];
                        CilMain.Where.Push($"field '{cilField.Name}'");

                        if (cilField.InitialValue.Length != 0)
                        {
                            throw CilMain.Where.Exception("unsupported InitialValue in field");
                        }

                        var myField = new JavaField();
                        myField.Name  = CilMain.MakeValidMemberName(cilField.Name);
                        myField.Class = jclass;
                        myField.Flags = AttributesToAccessFlags(
                            cilField.Attributes,
                            (cilType.HasNestedTypes || cilType.HasGenericParameters));

                        if (cilType.IsEnum)
                        {
                            myField.Type = CilType.From(cilField.FieldType);

                            if (cilField.Constant != null)
                            {
                                myField.InitConstant(cilField.Constant, CilMain.Where);
                            }
                        }
                        else
                        {
                            myField.Type = ValueUtil.GetBoxedFieldType(null, cilField);

                            if (((CilType)myField.Type).IsValueClass)
                            {
                                myField.Constant = cilField;
                            }

                            else
                            {
                                if (cilField.Constant != null)
                                {
                                    myField.InitConstant(cilField.Constant, CilMain.Where);
                                }

                                if (((CilType)myField.Type).IsVolatile)
                                {
                                    myField.Flags |= JavaAccessFlags.ACC_VOLATILE;
                                }
                            }
                        }

                        jclass.Fields.Add(myField);

                        CilMain.Where.Pop();
                    }
                }
            }
        }
Exemple #17
0
        public static JavaClass FixClass(JavaClass fromClass, CilType fromType)
        {
            JavaType  interfaceType  = InterfaceType(fromType);
            JavaClass interfaceClass = null;

            foreach (var method in fromClass.Methods)
            {
                if ((method.Flags & JavaAccessFlags.ACC_STATIC) == 0 && method.Code == null)
                {
                    if (method.Name == "<init>")
                    {
                        GenerateConstructor(method, fromType);
                    }
                    else if (method.Name == "Invoke")
                    {
                        if (interfaceClass != null)
                        {
                            break;
                        }

                        interfaceClass = MakeInterface(fromClass, method, interfaceType.ClassName);
                        GenerateInvoke(method, fromType, interfaceType);
                    }
                    else if (method.Name == "BeginInvoke")
                    {
                        if (interfaceClass == null)
                        {
                            break;
                        }

                        GenerateBeginInvoke();
                        continue;
                    }
                    else if (method.Name == "EndInvoke")
                    {
                        GenerateEndInvoke();
                        continue;
                    }
                    else
                    {
                        break;
                    }

                    method.Flags &= ~JavaAccessFlags.ACC_ABSTRACT;
                }
            }

            if (interfaceClass == null)
            {
                throw CilMain.Where.Exception("invalid delegate class");
            }

            return(interfaceClass);

            //
            //
            //

            JavaClass MakeInterface(JavaClass fromClass, JavaMethod fromMethod, string newName)
            {
                var newClass = CilMain.CreateInnerClass(fromClass, newName,
                                                        JavaAccessFlags.ACC_PUBLIC
                                                        | JavaAccessFlags.ACC_ABSTRACT
                                                        | JavaAccessFlags.ACC_INTERFACE);

                var newMethod = new JavaMethod(newClass, fromMethod);

                newMethod.Flags = JavaAccessFlags.ACC_PUBLIC
                                  | JavaAccessFlags.ACC_ABSTRACT;
                if (IsPrimitive(newMethod.ReturnType))
                {
                    // primitive return value is translated to java.lang.Object,
                    // because the delegate target may return a generic type that
                    // is specialized for the primitive type in the delegate.
                    // see also GenerateInvoke and LoadFunction
                    newMethod.ReturnType = JavaType.ObjectType;
                }
                newClass.Methods.Add(newMethod);

                return(newClass);
            }

            //
            //
            //

            void GenerateConstructor(JavaMethod method, CilType dlgType)
            {
                var code = method.Code = new JavaCode();

                code.Method       = method;
                code.Instructions = new List <Instruction>();

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

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

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

                code.NewInstruction(0x19 /* aload_0 */, null, (int)0);
                code.NewInstruction(0x19 /* aload_1 */, null, (int)1);
                code.NewInstruction(0x19 /* aload_2 */, null, (int)2);

                code.NewInstruction(0xB7 /* invokespecial */,
                                    new JavaType(0, 0, method.Class.Super),
                                    new JavaMethodRef("<init>", JavaType.VoidType,
                                                      JavaType.ObjectType, JavaType.ObjectType));

                code.NewInstruction(0xB1 /* return (void) */, null, null);

                if (code.MaxStack < 3)
                {
                    code.MaxStack = 3;
                }
                code.MaxLocals = 3 + dlgType.GenericParametersCount;
            }

            //
            //
            //

            void GenerateInvoke(JavaMethod method, CilType dlgType, JavaType ifcType)
            {
                var code = method.Code = new JavaCode();

                code.Method       = method;
                code.Instructions = new List <Instruction>();
                code.StackMap     = new JavaStackMap();

                code.NewInstruction(0x19 /* aload_0 */, null, (int)0);
                code.NewInstruction(0xB4 /* getfield */,
                                    new JavaType(0, 0, "system.Delegate"),
                                    new JavaFieldRef("invokable", JavaType.ObjectType));

                code.NewInstruction(0xC0 /* checkcast */, ifcType, null);
                code.StackMap.PushStack(JavaType.ObjectType);

                int index = 1;

                for (int i = 0; i < method.Parameters.Count; i++)
                {
                    var paramType = (CilType)method.Parameters[i].Type;
                    code.NewInstruction(paramType.LoadOpcode, null, index);
                    code.StackMap.PushStack(paramType);

                    if (paramType.IsGenericParameter && (!paramType.IsByReference))
                    {
                        // invoke the helper method which identifies our boxed
                        // primitives and re-boxes them as java boxed values.
                        // see also: GenericType::DelegateParameterin baselib.
                        GenericUtil.LoadMaybeGeneric(
                            paramType.GetMethodGenericParameter(), code);
                        code.NewInstruction(0xB8 /* invokestatic */,
                                            SystemDelegateUtilType, DelegateParameterMethod);
                        code.StackMap.PopStack(CilMain.Where);
                    }
                    index += paramType.Category;
                }

                var returnType = (CilType)method.ReturnType;

                if (IsPrimitive(returnType))
                {
                    // primitive return value is translated to java.lang.Object,
                    // because the delegate target may return a generic type that
                    // is specialized for the primitive type in the delegate.
                    // see also GenerateInvoke and LoadFunction
                    var adjustedMethod = new JavaMethodRef(
                        method.Name, JavaType.ObjectType, method.Parameters);
                    code.NewInstruction(0xB9 /* invokeinterface */, ifcType, adjustedMethod);
                }
                else
                {
                    code.NewInstruction(0xB9 /* invokeinterface */, ifcType, method);
                }

                code.StackMap.ClearStack();
                code.StackMap.PushStack(returnType);

                if (returnType.IsGenericParameter && (!returnType.IsByReference))
                {
                    GenericUtil.LoadMaybeGeneric(
                        returnType.GetMethodGenericParameter(), code);
                    code.NewInstruction(0xB8 /* invokestatic */,
                                        SystemDelegateUtilType, DelegateReturnValueMethod);
                    code.StackMap.PopStack(CilMain.Where);
                }
                else if (IsPrimitive(returnType))
                {
                    // if the delegate returns a primitive type, we need to unbox
                    // the object returned by the method we just called.  it will be
                    // a java boxed primitive (e.g. java.lang.Integer) if the called
                    // method actually returns a primitive, due to the boxing done
                    // by the invokedynamic mechanism.  if the called method returns
                    // a generic type, it will be our boxed type, e.g. system.Int32.
                    //
                    // see also DelegateReturnValueX helper methods in baselib,
                    // and MakeInterface and LoadFunction in this file.
                    var helperMethod = new JavaMethodRef(
                        DelegateReturnValueMethod.Name + returnType.ToDescriptor(),
                        returnType, JavaType.ObjectType);
                    code.NewInstruction(0xB8 /* invokestatic */,
                                        SystemDelegateUtilType, helperMethod);
                }

                code.NewInstruction(returnType.ReturnOpcode, null, index);
                code.StackMap.PopStack(CilMain.Where);

                code.MaxStack  = code.StackMap.GetMaxStackSize(CilMain.Where);
                code.MaxLocals = index;
            }

            //
            //
            //

            void GenerateBeginInvoke()
            {
            }

            //
            //
            //

            void GenerateEndInvoke()
            {
            }
        }