Example #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);
        }
Example #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);
            }
        }
Example #3
0
        public static bool CheckCast(CilType castType, bool @throw, JavaCode code)
        {
            if (object.ReferenceEquals(castType, GenericArrayType) ||
                (castType.IsArray && (castType.IsInterface ||
                                      castType.IsGenericParameter ||
                                      castType.ClassName == JavaType.ObjectType.ClassName ||
                                      castType.ClassName == CilType.SystemValueType.ClassName)))
            {
                // if casting to Object[], ValueType[], to an array of interface type,
                // or to an array of a generic parameter, we can't rely on a simple
                // 'checkcast' or 'instanceof', because the jvm will permit the cast
                // of a value type array to the aforementioned reference types.
                //
                // instead, we generate a call to system.Array.CheckCast in baselib,
                // except if we are generating code for the system.Array class itself.

                if (code.Method.Class.Name.StartsWith("system.Array"))
                {
                    return(false);
                }

                // note the caller of this method already popped the stack once.
                // which we have to undo that, before we push anything else.
                code.StackMap.PushStack(JavaType.ObjectType);   // array

                var method = new JavaMethodRef("CheckCast", JavaType.ObjectType);
                method.Parameters.Add(new JavaFieldRef("", JavaType.ObjectType));

                if (object.ReferenceEquals(castType, GenericArrayType) ||
                    castType.IsGenericParameter)
                {
                    method.Parameters.Add(new JavaFieldRef("", CilType.SystemTypeType));
                    GenericUtil.LoadMaybeGeneric(castType, code);
                    // CilType.SystemTypeType pushed to the stack
                }
                else
                {
                    method.Parameters.Add(new JavaFieldRef("", JavaType.ClassType));
                    code.NewInstruction(0x12 /* ldc */, castType.AdjustRank(-1), null);
                    code.StackMap.PushStack(JavaType.ClassType);
                }

                method.Parameters.Add(new JavaFieldRef("", JavaType.BooleanType));
                code.NewInstruction(0x12 /* ldc */, null, (int)(@throw ? 1 : 0));
                code.StackMap.PushStack(JavaType.IntegerType);  // boolean

                code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType, method);

                code.StackMap.PopStack(CilMain.Where);  // boolean
                code.StackMap.PopStack(CilMain.Where);  // class/type
                code.StackMap.PopStack(CilMain.Where);  // array

                return(true);
            }

            return(false);
        }
Example #4
0
        internal static JavaCode CreateHelperMethod(JavaClass theClass, JavaMethodRef methodType,
                                                    int maxLocals, int maxStack)
        {
            var newMethod = new JavaMethod(theClass, methodType);

            newMethod.Flags = JavaAccessFlags.ACC_PUBLIC | JavaAccessFlags.ACC_BRIDGE;

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

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

            code.MaxLocals = maxLocals;
            code.MaxStack  = maxStack;

            theClass.Methods.Add(newMethod);
            return(code);
        }
Example #5
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);
        }
Example #6
0
        static CodeArrays()
        {
            var parameters = new List <JavaFieldRef>(4);

            parameters.Add(new JavaFieldRef("", JavaType.ObjectType));
            parameters.Add(new JavaFieldRef("", CilType.SystemTypeType));
            parameters.Add(new JavaFieldRef("", CilType.SystemValueType));
            parameters.Add(new JavaFieldRef("", JavaType.IntegerType));
            InitArrayMethod = new JavaMethodRef("Initialize", JavaType.VoidType, parameters);

            parameters = new List <JavaFieldRef>(3);
            parameters.Add(new JavaFieldRef("", JavaType.ObjectType));
            parameters.Add(new JavaFieldRef("", JavaType.IntegerType));
            parameters.Add(new JavaFieldRef("", JavaType.ObjectType));
            StoreArrayMethod = new JavaMethodRef("Store", JavaType.VoidType, parameters);

            parameters = new List <JavaFieldRef>(2);
            parameters.Add(new JavaFieldRef("", JavaType.ObjectType));
            parameters.Add(new JavaFieldRef("", JavaType.IntegerType));
            LoadArrayMethod = new JavaMethodRef("Load", JavaType.ObjectType, parameters);
        }
Example #7
0
        public void EnterMethod(CilType type, JavaMethodRef method, bool instanceMethod)
        {
            //
            // we expect the method definition to contain the suffix type parameters
            // (added by CilMethod.ImportGenericParameters), so we subtract their
            // number to determine the index of the first type parameter.  if this
            // is an instance method, we add one to account for 'this' argument.
            //

            var argumentIndex = method.Parameters.Count - type.GenericParameters.Count;

            if (instanceMethod)
            {
                argumentIndex++;
            }

            foreach (var genericParameter in type.GenericParameters)
            {
                var item = new GenericStackItem();
                item.Name  = genericParameter.JavaName;
                item.Index = ++argumentIndex;   // index always +1
                items.Add(item);
            }
        }
Example #8
0
        public static void Indirection(JavaCode code, Code cilOp)
        {
            var(name, opcodeType) = IndirectOpCodeToNameAndType(cilOp);
            bool isRef = opcodeType.Equals(JavaType.ObjectType);

            bool isLoad;

            if (cilOp >= Code.Ldind_I1 && cilOp <= Code.Ldind_Ref)
            {
                isLoad = true;
            }
            else
            {
                isLoad = false;
                var valueType = code.StackMap.PopStack(CilMain.Where);
                if (valueType.IsReference != isRef)
                {
                    throw new InvalidProgramException();
                }
            }

            var stackTop = (CilType)code.StackMap.PopStack(CilMain.Where);

            if (stackTop.IsGenericParameter)
            {
                if (isLoad)
                {
                    var resultType = GenericUtil.CastMaybeGeneric(stackTop, false, code);
                    if (resultType == stackTop && (!stackTop.Equals(JavaType.ObjectType)))
                    {
                        code.NewInstruction(0xC0 /* checkcast */, stackTop.AsWritableClass, null);
                        resultType = stackTop;
                    }
                    code.StackMap.PushStack(resultType);
                }
                else
                {
                    code.NewInstruction(0x5F /* swap */, null, null);
                    GenericUtil.ValueCopy(stackTop, code);
                }
                return;
            }

            //
            // non-generic object reference
            //

            var boxedType = stackTop as BoxedType;

            if (boxedType == null || boxedType.IsBoxedReference != isRef)
            {
                if (CodeSpan.LoadStore(isLoad, stackTop, opcodeType, null, code))
                {
                    return;
                }

                if (object.ReferenceEquals(stackTop, CodeArrays.GenericArrayType))
                {
                    // a byref parameter T[] gets translated to java.lang.Object,
                    // so we have to explicitly cast it to system.Reference
                    boxedType = new BoxedType(stackTop, false);
                    code.NewInstruction(0x5F /* swap */, null, null);
                    code.NewInstruction(0xC0 /* checkcast */,
                                        boxedType.AsWritableClass, null);
                    code.NewInstruction(0x5F /* swap */, null, null);
                }
                else
                {
                    throw new ArgumentException($"incompatible type '{stackTop}'");
                }
            }

            var unboxedType     = boxedType.UnboxedType;
            var unboxedTypeCode = unboxedType.IsReference ? 0 : unboxedType.PrimitiveType;

            JavaMethodRef method;

            if (CompareIndirectTypes(unboxedTypeCode, opcodeType.PrimitiveType))
            {
                // indirect access to a primitive or reference type, with a
                // reference type that represents the boxed form of the same type.

                if (isLoad)
                {
                    boxedType.GetValue(code);
                    if (unboxedType.IsReference)
                    {
                        // if we know the type of indirected value, cast to it
                        if (!unboxedType.Equals(JavaType.ObjectType))
                        {
                            code.NewInstruction(0xC0 /* checkcast */,
                                                unboxedType.AsWritableClass, null);
                        }
                    }
                    else
                    {
                        unboxedType = CilType.From(opcodeType);
                    }
                    code.StackMap.PushStack(unboxedType);
                }
                else
                {
                    // if we are storing a real array into a boxed reference of
                    // e.g., system.Array, then we have to create an array proxy
                    CodeArrays.MaybeGetProxy(CodeArrays.GenericArrayType, unboxedType, code);

                    boxedType.SetValueOV(code);
                }
                return;
            }

            // indirect access to a primitive value from a reference type that
            // represents some other a primitive value;  for example ldind.r4
            // from a system.Int32.  we call the "CodeNumber.Indirection methods"
            // helpers, defined in all baselib primitives, to assist.

            if (opcodeType.IsIntLike)
            {
                opcodeType = JavaType.IntegerType;
            }
            if (isLoad)
            {
                method = new JavaMethodRef("Get_" + name, opcodeType);
                code.StackMap.PushStack(CilType.From(opcodeType));
            }
            else
            {
                method = new JavaMethodRef("Set_" + name, JavaType.VoidType, opcodeType);
            }
            code.NewInstruction(0xB6 /* invokevirtual */, boxedType, method);
        }
Example #9
0
        public static void LoadFunction(JavaCode code, Mono.Cecil.Cil.Instruction cilInst)
        {
            if (cilInst.Operand is MethodReference implMethodRef)
            {
                var implMethod = CilMethod.From(implMethodRef);

                var(declType, declMethod, dlgMethodName) = FindInterfaceType(cilInst);

                if (dlgMethodName != null)
                {
                    // if this is an artificial delegate for a functional interface,
                    // then we can't actually instantiate this particular delegate,
                    // because its definition only exists in the DLL created by
                    // DotNetImporter;  see BuildDelegate there.  we fix the Newobj
                    // instruction to instantiate system.FunctionalInterfaceDelegate.

                    cilInst.Next.Operand = DelegateConstructor(cilInst.Next.Operand);

                    declMethod = new JavaMethodRef(dlgMethodName,
                                                   implMethod.ReturnType,
                                                   implMethod.Parameters);
                }

                if (IsPrimitive(declMethod.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 MakeInterface and GenerateInvoke
                    declMethod = new JavaMethodRef(
                        declMethod.Name, JavaType.ObjectType, declMethod.Parameters);
                }

                // select the method handle kind for the dynamic call site.
                // for a non-static invocation, we need to push an object reference.

                JavaMethodHandle.HandleKind callKind;
                if (implMethod.DeclType.IsInterface)
                {
                    callKind = JavaMethodHandle.HandleKind.InvokeInterface;
                }
                else
                {
                    callKind = JavaMethodHandle.HandleKind.InvokeVirtual;
                }

                if (cilInst.OpCode.Code == Code.Ldftn)
                {
                    if (implMethod.IsStatic)
                    {
                        callKind = JavaMethodHandle.HandleKind.InvokeStatic;
                    }

                    else
                    {
                        var  implMethodDef = CilMethod.AsDefinition(implMethodRef);
                        bool isVirtual     = implMethodDef.IsVirtual;
                        if (isVirtual && implMethodDef.DeclaringType.IsSealed)
                        {
                            isVirtual = false;
                        }

                        if (!isVirtual)
                        {
                            // non-virtual instance method
                            code.NewInstruction(0x59 /* dup */, null, null);
                            code.StackMap.PushStack(JavaType.ObjectType);
                        }
                        else
                        {
                            // virtual method should only be specified in 'ldvirtftn'
                            throw new Exception("virtual method referenced");
                        }
                    }
                }

                //
                // the method may take generic type parameters, i.e. the System.Type
                // parameters that are added at the end of the parameter list, by
                // CilMethod::ImportGenericParameters.  but when the delegate is
                // called, these parameters will not be pushed.  therefore we do
                // the following when assigning such a method to a delegate:
                //
                // (1) we select a different implementing method, i.e. the bridge
                // method generated by CreateCapturingBridgeMethod (see below),
                // which moves the type arguments to the head of the parameter list.
                // (2) we generate and push the type arguments at this time, via
                // calls to GenericUtil.LoadGeneric.
                // (3) we specify the type arguments as capture parameters of the
                // call site.  (see also JavaCallSite.)  this means the generated
                // proxy will inject these parameters when it calls the bridge
                // method from step (1), and that bridge method will push these
                // parameters at the end of the parameter list, when it invokes
                // the actual target method.
                //

                List <JavaFieldRef> TypeArgs    = null;
                JavaMethodRef       implMethod2 = implMethod;

                var implGenericMethod = implMethod.WithGenericParameters;
                if (implGenericMethod != implMethod)
                {
                    implMethod2 = new JavaMethodRef(
                        "delegate-bridge-" + implGenericMethod.Name,
                        implMethod.ReturnType, implMethod.Parameters);

                    var count1 = implMethod.Parameters.Count;
                    var count2 = implGenericMethod.Parameters.Count;
                    TypeArgs = implGenericMethod.Parameters.GetRange(count1, count2 - count1);

                    var callMethod = CilMain.GenericStack.EnterMethod(implMethodRef);
                    for (int i = count1; i < count2; i++)
                    {
                        GenericUtil.LoadGeneric(implGenericMethod.Parameters[i].Name, code);
                    }
                    for (int i = count1; i < count2; i++)
                    {
                        code.StackMap.PopStack(CilMain.Where);
                    }
                }

                // create a CallSite that implements the method signature
                // declMethod, in the functional interface declType, in order
                // to proxy-invoke the method implMethod.DeclType::implMethod.

                var callSite = new JavaCallSite(declType, declMethod,
                                                implMethod.DeclType, implMethod2,
                                                TypeArgs, callKind);

                code.NewInstruction(0xBA /* invokedynamic */, null, callSite);

                if (callKind != JavaMethodHandle.HandleKind.InvokeStatic)
                {
                    code.StackMap.PopStack(CilMain.Where);
                }

                code.StackMap.PushStack(CilType.From(declType));
            }
            else
            {
                throw new InvalidProgramException();
            }

            //
            // ldftn or ldvirtftn should be followed by newobj, which we can use
            // to identify the delegate, and therefore, the interface
            //

            (JavaType, JavaMethodRef, string) FindInterfaceType(
                Mono.Cecil.Cil.Instruction cilInst)
            {
                cilInst = cilInst.Next;
                if (cilInst != null && cilInst.OpCode.Code == Code.Newobj &&
                    cilInst.Operand is MethodReference constructorRef)
                {
                    var dlgType = CilType.From(constructorRef.DeclaringType);
                    if (dlgType.IsDelegate)
                    {
                        //
                        // check for an artificial delegate, generated to represent a
                        // java functional interface: (BuildDelegate in DotNetImporter)
                        //
                        // delegate type is marked [java.lang.attr.AsInterface],
                        // and is child of an interface type.
                        // interface type is marked [java.lang.attr.RetainName],
                        // and has one method.
                        //

                        var dlgType0 = CilType.AsDefinition(constructorRef.DeclaringType);
                        if (dlgType0.HasCustomAttribute("AsInterface"))
                        {
                            var ifcType0 = dlgType0.DeclaringType;
                            var ifcType  = CilType.From(ifcType0);
                            if (ifcType.IsInterface && ifcType.IsRetainName &&
                                ifcType0.HasMethods && ifcType0.Methods.Count == 1)
                            {
                                return(ifcType, null, ifcType0.Methods[0].Name);
                            }
                        }

                        //
                        // otherwise, a normal delegate, which may be generic, or plain.
                        // interface name is DelegateType$interface.
                        // we look for a method named Invoke.
                        //

                        foreach (var method in dlgType0.Methods)
                        {
                            if (method.Name == "Invoke")
                            {
                                return(InterfaceType(dlgType), CilMethod.From(method), null);
                            }
                        }
                    }
                }
                throw new InvalidProgramException();
            }

            //
            // create a method reference to delegate constructor from baselib:
            // system.MulticastDelegate::.ctor(object, object)
            //

            CilMethod DelegateConstructor(object Operand)
            {
                var baseType = CilType.AsDefinition(((MethodReference)Operand)
                                                    .DeclaringType).BaseType;

                if (baseType.Namespace != "System" || baseType.Name != "MulticastDelegate")
                {
                    throw CilMain.Where.Exception(
                              $"delegate base type is '{baseType.Name}', "
                              + "but expected 'System.MulticastDelegate'");
                }

                return(CilMethod.CreateDelegateConstructor());
            }
        }
Example #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()
             * {
             * }*/
        }
Example #11
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()
            {
            }
        }
Example #12
0
        bool Translate_Newobj(CilMethod callMethod)
        {
            if (callMethod.IsStatic)
            {
                return(false);
            }

            var newClass = callMethod.DeclType;

            if (callMethod.IsArrayMethod)
            {
                arrays.New(newClass, callMethod.Parameters.Count);
                return(true);
            }

            if (newClass.IsValueClass)
            {
                if (!callMethod.IsValueInit)
                {
                    return(false);
                }
            }
            else
            {
                if (!callMethod.IsConstructor)
                {
                    return(false);
                }

                if (newClass.Equals(JavaType.StringType) &&
                    code.Method.Class.Name != newClass.JavaName)
                {
                    // redirect the System.String constructor to system.String.New
                    var newMethod = new JavaMethodRef("New", newClass);
                    newMethod.Parameters = callMethod.Parameters;

                    code.NewInstruction(0xB8 /* invokestatic */,
                                        new JavaType(0, 0, newClass.JavaName), newMethod);

                    int n = callMethod.Parameters.Count;
                    while (n-- > 0)
                    {
                        stackMap.PopStack(CilMain.Where);
                    }
                    stackMap.PushStack(newClass);

                    return(true);
                }

                if (newClass.Equals(JavaType.ThrowableType))
                {
                    // generally we translate System.Exception to java.lang.Throwable,
                    // but not when allocating a new object
                    newClass = CilType.From(new JavaType(0, 0, newClass.JavaName));
                }
            }

            //
            // save any parameters pushed for the call to the constructor
            //

            int localIndex = SaveMethodArguments(callMethod);

            code.NewInstruction(0xBB /* new */, newClass.AsWritableClass, null);
            stackMap.PushStack(newClass);
            code.NewInstruction(0x59 /* dup */, null, null);
            stackMap.PushStack(newClass);

            if (newClass.IsValueClass)
            {
                // new value type object.  first call the default constructor,
                // to allocate the object.  then call the constructor provided
                // in the Newobj instruction, to initialize the new object

                var defaultConstructor = new CilMethod(newClass);
                PushGenericArguments(defaultConstructor);
                code.NewInstruction(0xB7 /* invokespecial */, newClass,
                                    defaultConstructor.WithGenericParameters);

                // the defaul constructor accepted generic parameters, if any,
                // and they should be discarded now

                int numGeneric =
                    defaultConstructor.WithGenericParameters.Parameters.Count;

                while (numGeneric-- > 0)
                {
                    stackMap.PopStack(CilMain.Where);
                }

                // if Newobj specifies a non-default constructor, then call it

                int numNonGeneric = callMethod.Parameters.Count;
                if (numNonGeneric != 0)
                {
                    code.NewInstruction(0x59 /* dup */, null, null);

                    LoadMethodArguments(callMethod, localIndex);

                    code.NewInstruction(0xB6 /* invokevirtual */, newClass, callMethod);

                    while (numNonGeneric-- > 0)
                    {
                        stackMap.PopStack(CilMain.Where);
                    }
                }

                stackMap.PopStack(CilMain.Where);
            }
            else
            {
                //
                // new reference type object
                //

                LoadMethodArguments(callMethod, localIndex);
                PushGenericArguments(callMethod);

                code.NewInstruction(0xB7 /* invokespecial */, newClass.AsWritableClass,
                                    callMethod.WithGenericParameters);

                ClearMethodArguments(callMethod, false);
            }

            return(true);
        }
Example #13
0
        bool ConvertVirtualToStaticCall(CilType callClass, CilMethod callMethod)
        {
            if (callClass.ClassName == callClass.JavaName)
            {
                if (callClass.ClassName == "system.FunctionalInterfaceDelegate" &&
                    callMethod.Name == "AsInterface")
                {
                    // a call to system.FunctionalInterfaceDelegate::AsInterface()
                    // should be fixed to expect an 'object' return type, and then
                    // cast that return type to the proper interface
                    var tempMethod = new JavaMethodRef(callMethod.Name, JavaType.ObjectType);
                    code.NewInstruction(0xB6 /* invokevirtual */, callClass, tempMethod);
                    code.NewInstruction(0xC0 /* checkcast */, callMethod.ReturnType, null);
                    stackMap.PopStack(CilMain.Where);
                    stackMap.PushStack(callMethod.ReturnType);
                    return(true);
                }

                if (callMethod.IsExternal &&
                    NativeMethodClasses.TryGetValue(callClass.ClassName,
                                                    out var altClassName))
                {
                    // a call to an instance method System.NameSpace.Class::Method,
                    // which is implemented only as a native method, is translated
                    // into a static call to some other class where the method is
                    // implemented.  such implementing classes are listed in the
                    // NativeMethodClasses dictionary the bottom of this file.

                    var altMethodName    = callMethod.Name;
                    int altMethodNameIdx = altMethodName.IndexOf(CilMain.OPEN_PARENS);
                    if (altMethodNameIdx != -1)
                    {
                        altMethodName = altMethodName.Substring(0, altMethodNameIdx);
                    }

                    var tempMethod = new JavaMethodRef(altMethodName, callMethod.ReturnType);
                    var parameters = new List <JavaFieldRef>(callMethod.Parameters);
                    parameters.Insert(0, new JavaFieldRef("this", callClass));
                    tempMethod.Parameters = parameters;

                    code.NewInstruction(0xB8 /* invokestatic */,
                                        new JavaType(0, 0, altClassName), tempMethod);

                    ClearMethodArguments(callMethod, false);
                    PushMethodReturnType(callMethod);
                    return(true);
                }

                // don't bother adjusting the call if the program explicitly
                // refers to the java class rather than the simulated wrapper,
                // e.g. to java.lang.Throwable rather than System.Exception
                return(false);
            }

            if (callClass.Equals(JavaType.StringType) ||
                callClass.Equals(JavaType.ThrowableType) ||
                (callClass.Equals(JavaType.ObjectType) &&
                 callMethod.Name == "GetType" &&
                 callMethod.ToDescriptor() == "()Lsystem/Type;"))
            {
                // we map some basic .Net types their java counterparts, so we
                // can't invoke .Net instance methods on them directly.  instead,
                // we invoke a static method on our helper class.  for example:
                // ((System.String)x).CompareTo(y) -> system.String.CompareTo(x,y)

                var tempMethod = new JavaMethodRef(callMethod.Name, callMethod.ReturnType);
                var parameters = new List <JavaFieldRef>(callMethod.Parameters);
                parameters.Insert(0, new JavaFieldRef("this", callClass));
                tempMethod.Parameters = parameters;

                if (callClass.Equals(JavaType.ThrowableType) &&
                    callMethod.Name == "system-Exception-GetType")
                {
                    // undo the effect of CilMethod::MethodIsShadowing upon calling
                    // the virtual/overriding GetType() from System.Exception, and
                    // instead call the static system.Object.GetType()
                    tempMethod.Name    = "GetType";
                    callClass          = CilType.From(new JavaType(0, 0, "system.Object"));
                    parameters[0].Type = JavaType.ObjectType;
                }

                else
                {
                    CilMethod.FixNameForVirtualToStaticCall(tempMethod, callClass);
                }

                code.NewInstruction(0xB8 /* invokestatic */,
                                    new JavaType(0, 0, callClass.JavaName), tempMethod);

                ClearMethodArguments(callMethod, false);
                PushMethodReturnType(callMethod);

                return(true);
            }

            if (callClass.JavaName == null &&
                callClass.Equals(JavaType.ClassType) &&
                callMethod.Name == "GetRuntimeType")
            {
                // convert virtual call to RuntimeTypeHandle.GetRuntimeType
                // to a static call to system.RuntimeType

                code.NewInstruction(0xB8 /* invokestatic */,
                                    CilType.SystemRuntimeTypeType,
                                    new JavaMethodRef(
                                        callMethod.Name, callMethod.ReturnType,
                                        JavaType.ObjectType));

                ClearMethodArguments(callMethod, false);
                PushMethodReturnType(callMethod);

                return(true);
            }

            return(false);
        }