Example #1
0
        int ImportGenericParameters(TypeReference fromType)
        {
            if (!fromType.HasGenericParameters)
            {
                return(0);
            }
            int numGeneric = fromType.GenericParameters.Count;

            if (numGeneric != 0)
            {
                GenericParameters = new List <CilType>(numGeneric);
                for (int i = 0; i < numGeneric; i++)
                {
                    var genericParameter = CilType.From(fromType.GenericParameters[i]);
                    GenericParameters.Add(genericParameter);
                }
                Flags |= HAS_GEN_PRM;
            }
            return(numGeneric);
        }
Example #2
0
        void CastToClass(object data)
        {
            var srcType = (CilType)code.StackMap.PopStack(CilMain.Where);

            if (!(srcType.IsReference && data is TypeReference))
            {
                throw new InvalidProgramException();
            }

            byte op;
            var  dstType = (CilType)CilType.From((TypeReference)data);

            if (GenericUtil.ShouldCallGenericCast(srcType, dstType))
            {
                code.StackMap.PushStack(srcType);
                // casting to a generic type is done via GenericType.TestCast
                GenericUtil.CastToGenericType((TypeReference)data, 1, code);
                code.StackMap.PopStack(CilMain.Where); // srcType
                op = 0xC0;                             // checkcast
            }
            else
            {
                // cast to a non-generic type
                if (dstType.Equals(srcType) || dstType.Equals(JavaType.ObjectType))
                {
                    op = 0x00; // nop
                }
                else if (dstType.IsReference)
                {
                    CodeArrays.CheckCast(dstType, true, code);
                    op = 0xC0; // checkcast
                }
                else
                {
                    throw new InvalidProgramException();
                }
            }

            code.NewInstruction(op, dstType, null);
            code.StackMap.PushStack(dstType);
        }
Example #3
0
        public void Length()
        {
            var stackTop = (CilType)stackMap.PopStack(CilMain.Where);

            if (object.ReferenceEquals(stackTop, GenericArrayType))
            {
                // length of a generic array T[]
                code.NewInstruction(0xB8 /* invokestatic */,
                                    new JavaType(0, 0, "java.lang.reflect.Array"),
                                    new JavaMethodRef("getLength", JavaType.IntegerType, JavaType.ObjectType));
            }
            else if (stackTop.IsArray)
            {
                code.NewInstruction(0xBE /* arraylength */, null, null);
            }
            else
            {
                throw new InvalidProgramException();
            }
            stackMap.PushStack(CilType.From(JavaType.IntegerType));
        }
Example #4
0
        void LinkSuperTypes(TypeDefinition defType)
        {
            int n = defType.HasInterfaces ? defType.Interfaces.Count : 0;

            SuperTypes = new List <CilType>(n + 1);
            SuperTypes.Add(CilType.From(
                               defType.BaseType ?? defType.Module.TypeSystem.Object));

            for (int i = 0; i < n; i++)
            {
                SuperTypes.Add(CilType.From(defType.Interfaces[i].InterfaceType));
            }

            for (int i = 0; i <= n; i++)
            {
                if (SuperTypes[i].HasGenericParameters || SuperTypes[i].HasGenericSuperType)
                {
                    Flags |= HAS_GEN_SUP;
                }
            }
        }
Example #5
0
        public static void Conversion(JavaCode code, Code cilOp)
        {
            var oldType = (CilType)code.StackMap.PopStack(CilMain.Where);

            var(newType, overflow, unsigned) = ConvertOpCodeToTypeCode(cilOp);
            int op;

            if (oldType.IsReference)
            {
                ConvertReference(code, oldType, newType);
                return;
            }

            if (newType == TypeCode.Single || newType == TypeCode.Double)
            {
                op = ConvertToFloat(code, oldType.PrimitiveType, newType, unsigned);
            }

            else if (overflow)
            {
                op = ConvertWithOverflow(code, oldType.PrimitiveType, newType);
            }

            else if (newType == TypeCode.Int64 || newType == TypeCode.UInt64)
            {
                op = ConvertToLong(code, oldType.PrimitiveType, newType);
            }

            else
            {
                op = ConvertToInteger(code, oldType.PrimitiveType, newType);
            }

            if (op != -1)
            {
                code.NewInstruction((byte)op, null, null);
            }

            code.StackMap.PushStack(CilType.From(new JavaType(newType, 0, null)));
        }
Example #6
0
        public static bool SubOffset(JavaType secondType, JavaCode code)
        {
            // make sure the first operand is a pointer span, not a real Span<T>
            var spanType1 = (CilType)code.StackMap.PopStack(CilMain.Where);

            if ((!spanType1.HasGenericParameters) &&
                spanType1.GenericParameters != null &&
                spanType1.GenericParameters[0] is CilType span1PointerType &&
                (!span1PointerType.IsGenericParameter))
            {
                var spanType2 = (CilType)secondType;

                // check if subtracting two pointer spans
                if ((!spanType2.HasGenericParameters) &&
                    spanType2.GenericParameters != null &&
                    spanType2.GenericParameters[0] is CilType span2PointerType &&
                    (!span2PointerType.IsGenericParameter))
                {
                    code.NewInstruction(0xB6 /* invokevirtual */, SpanType,
                                        new JavaMethodRef("Subtract",
                                                          JavaType.LongType, spanType2));
                    code.StackMap.PushStack(CilType.From(JavaType.LongType));
                    return(true);
                }

                // check if subtracting an offset from a pointer span
                if (spanType2.Equals(JavaType.IntegerType))
                {
                    code.NewInstruction(0xB6 /* invokevirtual */, SpanType,
                                        new JavaMethodRef("Subtract",
                                                          SpanType, spanType2));
                    code.StackMap.PushStack(SpanType);
                    return(true);
                }
            }

            code.StackMap.PushStack(spanType1);
            return(false);
        }
Example #7
0
 public static void Sizeof(object data, JavaCode code)
 {
     if (data is TypeReference operandTypeReference)
     {
         var myType = CilType.From(operandTypeReference);
         if (myType.IsValueClass)
         {
             // compiler generated IL typically calculates the stackalloc
             // total buffer size, for primitive types, and uses 'sizeof'
             // for values types.  but it also uses 'sizeof' for generic
             // types, which may stand for a primitive type.
             GenericUtil.LoadMaybeGeneric(myType, code);
             code.NewInstruction(0xB8 /* invokestatic */, SpanType,
                                 new JavaMethodRef("Sizeof" + CilMain.EXCLAMATION,
                                                   JavaType.IntegerType, CilType.SystemTypeType));
             code.StackMap.PopStack(CilMain.Where);  // generic type
             code.StackMap.PushStack(JavaType.IntegerType);
             return;
         }
     }
     throw new InvalidProgramException();
 }
Example #8
0
        public static void CastToGenericType(TypeReference fromType, int throwBool, JavaCode code)
        {
            var genericMark = CilMain.GenericStack.Mark();

            GenericUtil.LoadMaybeGeneric(CilMain.GenericStack.EnterType(fromType), code);
            CilMain.GenericStack.Release(genericMark);

            code.NewInstruction(0x12 /* ldc */, null, throwBool);
            code.StackMap.PushStack(CilType.From(JavaType.IntegerType));

            var parameters = new List <JavaFieldRef>();

            parameters.Add(new JavaFieldRef("", JavaType.ObjectType));
            parameters.Add(new JavaFieldRef("", CilType.SystemTypeType));
            parameters.Add(new JavaFieldRef("", JavaType.BooleanType));

            code.NewInstruction(0xB8 /* invokestatic */, GenericUtil.SystemGenericType,
                                new JavaMethodRef("TestCast",
                                                  JavaType.ObjectType, parameters));
            code.StackMap.PopStack(CilMain.Where);
            code.StackMap.PopStack(CilMain.Where);
        }
Example #9
0
        void StoreObject(object data)
        {
            if (data is TypeReference typeRef)
            {
                var dataType = CilType.From(typeRef);

                var valueType = (CilType)code.StackMap.PopStack(CilMain.Where);
                var intoType  = (CilType)code.StackMap.PopStack(CilMain.Where);
                if (CodeSpan.LoadStore(false, intoType, null, dataType, code))
                {
                    return;
                }

                if (intoType is BoxedType intoBoxedType &&
                    dataType.PrimitiveType ==
                    intoBoxedType.UnboxedType.PrimitiveType)
                {
                    // 'stobj primitive' with a primitive value on the stack,
                    // or 'stobj primitive[]' with a primitive array on the stack
                    if ((!dataType.IsReference) || dataType.IsArray)
                    {
                        intoBoxedType.SetValueOV(code);
                        return;
                    }
                }

                code.StackMap.PushStack(intoType);
                code.StackMap.PushStack(valueType);

                GenericUtil.ValueCopy(dataType, code, true);
                code.StackMap.PopStack(CilMain.Where);
                code.StackMap.PopStack(CilMain.Where);
            }
            else
            {
                throw new InvalidProgramException();
            }
        }
Example #10
0
 void EnterGenericInstance(IGenericInstance instance, IGenericParameterProvider provider)
 {
     if (instance.HasGenericArguments)
     {
         foreach (var genericElement in provider.GenericParameters)
         {
             var item            = new GenericStackItem();
             var genericArgument = instance.GenericArguments[genericElement.Position];
             if (genericArgument is ArrayType genericArgumentAsArray)
             {
                 item.GenericInstance = genericArgumentAsArray.ElementType as GenericInstanceType;
             }
             else
             {
                 item.GenericInstance = genericArgument as GenericInstanceType;
             }
             item.GenericParent = instance;
             item.Name          = CilType.GenericParameterFullName(genericElement);
             item.Type          = CilType.From(genericArgument);
             items.Add(item);
         }
     }
 }
Example #11
0
        static void BitwiseNot(JavaCode code, TypeCode typeCode)
        {
            var jtype = new JavaType(typeCode, 0, null);

            code.StackMap.PushStack(CilType.From(jtype));
            code.StackMap.PushStack(jtype);

            byte op = 0x82; // ixor

            code.NewInstruction(0x02 /* iconst_m1 */, null, null);
            if (typeCode == TypeCode.Int64)
            {
                code.NewInstruction(0x85 /* i2l */, null, null);
                op++; // lxor
            }
            else if (typeCode != TypeCode.Int32)
            {
                throw new InvalidProgramException();
            }

            code.NewInstruction(op, null, null);
            code.StackMap.PopStack(CilMain.Where);
        }
Example #12
0
        public CilType EnterType(TypeReference fromType)
        {
            var myType = CilType.From(fromType);

            if (fromType is ArrayType fromArrayType)
            {
                EnterType(fromArrayType.ElementType);
            }
            else
            {
                if (fromType.HasGenericParameters)
                {
                    EnterGenericProvider(fromType, myType, -1);
                }
                if (fromType.IsGenericInstance)
                {
                    var genericInstance = (GenericInstanceType)fromType;
                    EnterGenericInstance(genericInstance, genericInstance.ElementType);
                }
            }

            return(myType);
        }
Example #13
0
        public void Load(Code op, object data, Mono.Cecil.Cil.Instruction inst)
        {
            stackMap.PopStack(CilMain.Where);   // pop index
            CilType  arrayType = (CilType)stackMap.PopStack(CilMain.Where);
            CilType  elemType  = null;
            TypeCode elemCode  = 0;

            switch (op)
            {
            case Code.Ldelem_Ref:
                if (arrayType.IsValueClass)
                {
                    throw new InvalidProgramException();
                }
                elemType = arrayType.AdjustRank(-1);
                break;

            case Code.Ldelem_Any:

                //if (data is ArrayType || (! (data is TypeReference)))
                if (!(data is TypeReference))
                {
                    throw new InvalidProgramException();
                }
                elemType = CilType.From((TypeReference)data);

                // check if array element is loaded and boxed, only to check
                // its type or check if null.  in this case we take a shortcut
                // and load directly from the array, without making a copy.

                var next = inst.Next;
                if (next != null && next.OpCode.Code == Code.Box)
                {
                    next = next.Next;
                    if (next != null && CodeBuilder.IsBrTrueBrFalseIsInst(next.OpCode.Code))
                    {
                        code.NewInstruction(0xB8 /* invokestatic */,
                                            new JavaType(0, 0, "java.lang.reflect.Array"),
                                            new JavaMethodRef("get", JavaType.ObjectType, JavaType.ObjectType, JavaType.IntegerType));
                        stackMap.PushStack(elemType);
                        return;
                    }
                }

                break;

            case Code.Ldelem_I1:
            case Code.Ldelem_U1:   elemCode = TypeCode.Byte;   break;

            case Code.Ldelem_U2:                        elemCode = TypeCode.Char;   break;

            case Code.Ldelem_I2:                        elemCode = TypeCode.Int16;  break;

            case Code.Ldelem_I4:
            case Code.Ldelem_U4:   elemCode = TypeCode.Int32;  break;

            case Code.Ldelem_I8:
            case Code.Ldelem_I:    elemCode = TypeCode.Int64;  break;

            case Code.Ldelem_R4:                        elemCode = TypeCode.Single; break;

            case Code.Ldelem_R8:                        elemCode = TypeCode.Double; break;

            default:                                    throw new InvalidProgramException();
            }

            if (elemCode != 0)
            {
                elemType = CilType.From(new JavaType(elemCode, 0, null));
            }
            Load(arrayType, elemType, inst);
        }
Example #14
0
        public static void Compare(JavaCode code, Code cilOp, Mono.Cecil.Cil.Instruction cilInst)
        {
            //
            // each cil comparison instruction checks one relation (equals,
            // grater than, or less than) and pushes integer 0 or 1.
            // in contrast, jvm compares two values and returns -1, 0, or 1.
            // we simulate ceq/cgt/clt as a compare and branch sequence:
            //
            // call to System.UInt{16,32}.CompareTo (for unsigned compare)
            // comparison like lcmp/fcmpl/dcmpl (for long/float/double)
            // branch like if_acmpeq/if_icmplt/ifne (depends on test)
            // iconst_0
            // goto next instruction
            // branch label:
            // iconst_1
            //

            if (cilInst.Next == null)
            {
                throw new InvalidProgramException();
            }

            //
            // first, the comparison test.  this is done in a helper method
            // which returns the opcode for the branch following the test.
            //

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

            byte op = (cilOp == Code.Ceq)
                    ? TestEq(code, stackTop, stackTop2, cilInst)
                    : TestGtLt(code, stackTop, stackTop2,
                               /* if greater than */ (cilOp == Code.Cgt ||
                                                      /* (vs less than) */ cilOp == Code.Cgt_Un),
                               /* if unsigned */ (cilOp == Code.Cgt_Un ||
                                                  /* or unordered */ cilOp == Code.Clt_Un));
            //
            // as branch labels, we generally use the offset of the source
            // cil instruction;  in this case, we need a temporary label
            // which does not correspond to any cil instruction, so we will
            // use offset+1 (knowing that ceq/cgt/clt is two bytes long)
            //

            ushort label1 = (ushort)(cilInst.Offset + 1);

            code.NewInstruction(op, null, label1);
            code.StackMap.SaveFrame(label1, true, CilMain.Where);

            //
            // if the test failed and we fall through, push 0 and branch
            // to the next cil instruction.  otherwise push 1.
            //

            ushort label2 = (ushort)cilInst.Next.Offset;

            code.NewInstruction(0x03 /* iconst_0 */, null, null);
            code.StackMap.PushStack(CilType.From(JavaType.IntegerType));

            code.NewInstruction(0xA7 /* goto */, null, label2);
            code.StackMap.SaveFrame(label2, true, CilMain.Where);

            code.NewInstruction(0x04 /* iconst_1 */, null, null, (ushort)label1);
        }
Example #15
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 #16
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);
            }
        }
Example #17
0
        bool ImportParameters(MethodReference fromMethod)
        {
            bool appendSuffix = false;

            int n = fromMethod.HasParameters ? fromMethod.Parameters.Count : 0;

            Parameters = new List <JavaFieldRef>(n);

            for (int i = 0; i < n; i++)
            {
                var fromParameterType = fromMethod.Parameters[i].ParameterType;
                var paramType         = CilType.From(fromParameterType);

                if (paramType.IsPointer)
                {
                    if (paramType.IsValueClass || (!paramType.IsReference))
                    {
                        paramType = CilType.MakeSpanOf(paramType);
                    }
                    else
                    {
                        throw CilMain.Where.Exception("invalid pointer type in parameter");
                    }
                }

                if (paramType.IsGenericParameter)
                {
                    appendSuffix = true;
                    var nm = "-generic-";
                    if (paramType.IsArray)
                    {
                        nm += "array-" + paramType.ArrayRank + "-";
                    }
                    if (paramType.IsByReference)
                    {
                        nm = "-ref" + nm.Replace("&", "");
                    }
                    nm       += "$" + ((GenericParameter)fromParameterType.GetElementType()).Position;
                    paramType = CilType.WrapMethodGenericParameter(paramType, nm);
                    Flags    |= GEN_ARGS;
                }

                if (paramType.IsByReference)
                {
                    if (paramType.IsValueClass)
                    {
                        paramType    = paramType.MakeByRef();
                        appendSuffix = true;
                    }
                    else
                    {
                        // byref of any reference type parameter becomes system.Reference,
                        // so add a unique method name suffix
                        var paramBoxedType = new BoxedType(paramType, false);
                        paramType     = paramBoxedType;
                        appendSuffix |= paramBoxedType.IsBoxedReference;
                    }
                }

                if (!appendSuffix)
                {
                    appendSuffix |= fromParameterType.IsGenericInstance;

                    if (!paramType.IsReference)
                    {
                        appendSuffix |= ShouldRenamePrimitive(paramType);
                    }
                }

                Parameters.Add(new JavaFieldRef("", paramType));
            }

            var returnType = CilType.From(fromMethod.ReturnType);

            if (returnType.IsGenericParameter)
            {
                returnType = CilType.WrapMethodGenericParameter(returnType);
            }
            else if (returnType.IsByReference)
            {
                returnType = new BoxedType(returnType, false);
            }
            ReturnType = returnType;

            appendSuffix |= fromMethod.ReturnType.IsGenericInstance;

            return(appendSuffix);
Example #18
0
        void LoadConstant(Code op, Mono.Cecil.Cil.Instruction inst)
        {
            JavaType pushType;
            object   pushValue;
            byte     pushOpcode;

            if (op == Code.Ldnull)
            {
                pushValue  = null;
                pushOpcode = 0x01; // aconst_null
                pushType   = JavaStackMap.Null;
            }
            else
            {
                var data = inst.Operand;
                pushOpcode = 0x12;            // ldc

                if (data is string stringVal) // Code.Ldstr
                {
                    pushValue = stringVal;
                    pushType  = JavaType.StringType;
                }
                else if (data is double doubleVal) // Code.Ldc_R8
                {
                    pushValue = doubleVal;
                    pushType  = JavaType.DoubleType;
                }
                else if (data is float floatVal) // Code.Ldc_R4
                {
                    pushValue = floatVal;
                    pushType  = JavaType.FloatType;
                }
                else if (data is long longVal) // Code.Ldc_I8
                {
                    pushValue = longVal;
                    pushType  = JavaType.LongType;
                }
                else if (IsAndBeforeShift(inst, code))
                {
                    // jvm shift instructions mask the shift count, so
                    // eliminate AND-ing with 31 and 63 prior to a shift
                    code.NewInstruction(0x00 /* nop */, null, null);
                    return;
                }
                else
                {
                    pushType = JavaType.IntegerType;

                    if (data is int intVal) // Code.Ldc_I4
                    {
                        pushValue = intVal;
                    }

                    else if (data is sbyte sbyteVal) // Code.Ldc_I4_S
                    {
                        pushValue = (int)sbyteVal;
                    }

                    else if (op >= Code.Ldc_I4_M1 && op <= Code.Ldc_I4_8)
                    {
                        pushValue = (int)(op - Code.Ldc_I4_0);
                    }

                    else
                    {
                        throw new InvalidProgramException();
                    }
                }
            }

            code.NewInstruction(pushOpcode, null, pushValue);
            stackMap.PushStack(CilType.From(pushType));
        }
Example #19
0
        static CatchClause CreateCatchClause(TryClause tryClause, ExceptionHandler cilClause)
        {
            // convert a CIL exception table entry to a CatchClause, while doing
            // some validity checks on the input.  in particular, we expect that
            // there are no gaps between catch clauses, and at most one finally
            // (or fault) clause within a protected region.

            var catchClause = new CatchClause();

            catchClause.catchStart = cilClause.HandlerStart.Offset;
            catchClause.catchEnd   = cilClause.HandlerEnd?.Offset ?? 0xFFFF;
            int handlerStart = catchClause.catchStart;

            if (catchClause.catchStart >= catchClause.catchEnd ||
                catchClause.catchStart < tryClause.tryEnd)
            {
                return(null);
            }

            if (cilClause.HandlerType == ExceptionHandlerType.Catch)
            {
                // note that we treat 'catch (System.Exception)'
                // as 'catch (Throwable)' so that our try/catch blocks
                // can really see all exceptions

                var myType = CilType.From(cilClause.CatchType);
                if (myType.JavaName == "system.Exception" && (!myType.Equals(ThrowableType)))
                {
                    throw CilMain.Where.Exception(
                              "catch of system.Exception (use System.Exception)");
                }
                if (myType.Equals(JavaType.ObjectType))
                {
                    catchClause.catchType = ThrowableType;
                }
                else
                {
                    catchClause.catchType = myType;
                }
                if (myType.HasGenericParameters)
                {
                    catchClause.catchFromType = cilClause.CatchType;
                }
            }

            else if (cilClause.HandlerType == ExceptionHandlerType.Filter)
            {
                catchClause.catchType       = ThrowableType;
                catchClause.filterCondStart = cilClause.FilterStart.Offset;
                handlerStart = catchClause.filterCondStart;

                if (catchClause.filterCondStart < tryClause.tryEnd)
                {
                    return(null);
                }
            }

            else if (cilClause.HandlerType == ExceptionHandlerType.Finally ||
                     cilClause.HandlerType == ExceptionHandlerType.Fault)
            {
                catchClause.catchType     = ThrowableType;
                catchClause.finallyClause = true;
                // note that we treat a 'fault' clause as a special form of a
                // 'finally' clause, so only one of these is allowed per 'try'.
                catchClause.faultClause =
                    (cilClause.HandlerType == ExceptionHandlerType.Fault);
            }
            else
            {
                return(null);
            }

            bool consecutiveClauses = true;

            if (tryClause.catchClauses.Count == 0)
            {
                consecutiveClauses = (handlerStart == tryClause.tryEnd);
            }
            else
            {
                foreach (var oldCatchClause in tryClause.catchClauses)
                {
                    if (handlerStart <= oldCatchClause.catchStart)
                    {
                        consecutiveClauses = false;
                    }
                    if (oldCatchClause.finallyClause)
                    {
                        consecutiveClauses = false;
                    }
                }
            }

            if (!consecutiveClauses)
            {
                throw CilMain.Where.Exception("non-consecutive clauses in a try block");
            }

            if (catchClause.catchEnd > tryClause.catchEnd)
            {
                tryClause.catchEnd = catchClause.catchEnd;
            }

            return(catchClause);
        }
Example #20
0
 static JavaType InterfaceType(CilType dlgType) =>
 CilType.From(new JavaType(0, 0, InterfaceName(dlgType)));
Example #21
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));
            }
        }
Example #22
0
        void UnboxObject(Code cilOp, object data)
        {
            if (data is TypeReference typeRef)
            {
                var dataType = CilType.From(typeRef);

                if (dataType.IsValueClass)
                {
                    if (dataType.IsGenericParameter)
                    {
                        if (cilOp == Code.Unbox_Any)
                        {
                            // unboxing (casting) a concrete type as a generic type
                            var stackTop = (CilType)code.StackMap.PopStack(CilMain.Where);
                            if (stackTop.Equals(JavaType.ObjectType) || dataType.Equals(stackTop))
                            {
                                code.NewInstruction(0x00 /* nop */, null, null);
                            }
                            else
                            {
                                code.NewInstruction(0xC0 /* checkcast */, dataType, null);
                            }
                            code.StackMap.PushStack(dataType);
                        }
                        else // plain Unbox
                        {
                            throw new InvalidProgramException();
                        }
                    }
                    else
                    {
                        code.StackMap.PopStack(CilMain.Where);
                        code.NewInstruction(0xC0 /* checkcast */, dataType, null);
                        code.StackMap.PushStack(dataType);
                    }
                }

                else if (!dataType.IsReference)
                {
                    var boxedType = new BoxedType(dataType, false);

                    var fromType = code.StackMap.PopStack(CilMain.Where);
                    if (!fromType.Equals(boxedType))
                    {
                        code.NewInstruction(0xC0 /* checkcast */, boxedType, null);
                    }

                    boxedType.GetValue(code);
                    code.StackMap.PushStack(dataType);
                }

                else
                {
                    if (cilOp == Code.Unbox_Any)
                    {
                        NullCheck();
                        CastToClass(data);
                    }
                    else // plain Unbox
                    {
                        throw new InvalidProgramException();
                    }
                }
            }
        }
Example #23
0
        void LoadObject(Code cilOp, object data)
        {
            if (data is TypeReference typeRef)
            {
                var dataType = CilType.From(typeRef);
                var fromType = (CilType)code.StackMap.PopStack(CilMain.Where);

                if (CodeSpan.LoadStore(true, fromType, null, dataType, code))
                {
                    return;
                }

                if ((!dataType.IsReference) && cilOp == Code.Ldobj &&
                    fromType is BoxedType fromBoxedType &&
                    dataType.PrimitiveType == fromBoxedType.UnboxedType.PrimitiveType)
                {
                    // 'ldobj primitive' with a corresponding boxed type on the stack.
                    // we implement by unboxing the boxed type into a primitive value.
                    fromBoxedType.GetValue(code);
                    stackMap.PushStack(fromBoxedType.UnboxedType);
                    return;
                }

                if (dataType.IsGenericParameter ||
                    (dataType.IsValueClass && dataType.Equals(fromType)))
                {
                    code.StackMap.PushStack(dataType);

                    if (SkipClone(cilInst.Next, fromType))
                    {
                        // see below for the several cases where we determine
                        // that we can safely avoid making a clone of the value
                        code.NewInstruction(0x00 /* nop */, null, null);
                    }
                    else if (dataType.IsGenericParameter)
                    {
                        GenericUtil.ValueClone(code);
                    }
                    else if (cilOp == Code.Ldobj)
                    {
                        code.NewInstruction(0x00 /* nop */, null, null);
                    }
                    else
                    {
                        CilMethod.ValueMethod(CilMethod.ValueClone, code);
                    }
                    return;
                }

                if (dataType.IsReference && cilOp == Code.Box)
                {
                    // 'box' is permitted on reference types, we treat it as a cast
                    code.StackMap.PushStack(fromType);
                    CastToClass(data);
                    return;
                }

                if (!dataType.IsReference)
                {
                    var boxedType = new BoxedType(dataType, false);
                    code.StackMap.PushStack(boxedType);
                    boxedType.BoxValue(code);
                    return;
                }
            }
            throw new InvalidProgramException();


            bool SkipClone(Mono.Cecil.Cil.Instruction next, CilType checkType)
            {
                if (checkType.IsByReference)
                {
                    return(true);
                }

                if (next == null)
                {
                    return(false);
                }
                var op = next.OpCode.Code;

                if (IsBrTrueBrFalseIsInst(op))
                {
                    // if 'ldobj' or 'box' is followed by a check for null,
                    // we don't actually need to clone just for the test
                    return(true);
                }

                if (op == Code.Box)
                {
                    if (next.Operand is TypeReference nextTypeRef)
                    {
                        // 'ldobj' may be followed by 'box', to load the value
                        // of a byref value type, and then box it into an object.
                        // effectively we only need to clone once, in such a case.
                        return(CilType.From(nextTypeRef).Equals(checkType));
                    }
                }

                var(storeType, _) = locals.GetLocalFromStoreInst(op, next.Operand);
                if (storeType != null)
                {
                    // 'ldobj' or 'box' may be followed by a store instruction.
                    // if storing into a variable of the same value type, the
                    // next instruction will copy the value, so skip clone.
                    return(storeType.Equals(checkType));
                }

                if (op == Code.Ret && checkType.IsClonedAtTop)
                {
                    // if the value on the stack was cloned/boxed at the top of
                    // the method, then we can avoid clone and return it directly.
                    // see also:  CilType.MakeClonedAtTop and its callers.
                    return(true);
                }

                if (op == Code.Unbox_Any)
                {
                    if (next.Operand is TypeReference nextTypeRef)
                    {
                        // 'ldobj' or 'box' may be followed by 'unbox' and
                        // then one of the instructions above, e.g. 'brtrue'
                        // or 'stloc'.  we still want to detect such a case
                        // and prevent a needless clone.
                        return(SkipClone(next.Next, CilType.From(nextTypeRef)));
                    }
                }

                return(false);
            }
        }
Example #24
0
        public static void Calculation(JavaCode code, Code cilOp,
                                       Mono.Cecil.Cil.Instruction cilInst)
        {
            if (cilOp == Code.And &&
                CodeBuilder.IsAndBeforeShift(cilInst.Previous, code))
            {
                // jvm shift instructions mask the shift count, so
                // eliminate AND-ing with 31 and 63 prior to a shift
                code.NewInstruction(0x00 /* nop */, null, null);
                return;
            }

            var stackTop1 = code.StackMap.PopStack(CilMain.Where);

            if (cilOp == Code.Sub && CodeSpan.SubOffset(stackTop1, code))
            {
                return;
            }
            var type1 = GetNumericTypeCode(stackTop1);

            if (cilOp == Code.Not)
            {
                BitwiseNot(code, type1);
                return;
            }

            byte op;

            if (cilOp == Code.Neg)
            {
                op = 0x74; // ineg
            }
            else
            {
                var stackTop2 = code.StackMap.PopStack(CilMain.Where);
                if ((cilOp == Code.Add || cilOp == Code.Add_Ovf_Un) &&
                    CodeSpan.AddOffset(stackTop1, stackTop2, code))
                {
                    return;
                }

                char kind;
                var  type2 = type1;
                type1 = GetNumericTypeCode(stackTop2);

                switch (cilOp)
                {
                case Code.Add:      op = 0x60; kind = 'A'; break;       // iadd

                case Code.Sub:      op = 0x64; kind = 'A'; break;       // isub

                case Code.Mul:      op = 0x68; kind = 'A'; break;       // imul

                case Code.Div:      op = 0x6C; kind = 'A'; break;       // idiv

                case Code.Rem:      op = 0x70; kind = 'A'; break;       // irem

                case Code.And:      op = 0x7E; kind = 'L'; break;       // iand

                case Code.Or:       op = 0x80; kind = 'L'; break;       // ior

                case Code.Xor:      op = 0x82; kind = 'L'; break;       // ixor

                case Code.Shl:      op = 0x78; kind = 'S'; break;       // ishl

                case Code.Shr:      op = 0x7A; kind = 'S'; break;       // ishr

                case Code.Shr_Un:   op = 0x7C; kind = 'S'; break;       // iushr

                case Code.Div_Un:
                case Code.Rem_Un:
                    op = 0x00; kind = 'U'; break;

                case Code.Add_Ovf:
                case Code.Sub_Ovf:
                case Code.Mul_Ovf:
                case Code.Add_Ovf_Un:
                case Code.Sub_Ovf_Un:
                case Code.Mul_Ovf_Un:
                    op = 0x00; kind = 'A'; break;

                default:            throw new InvalidProgramException();
                }

                bool ok = true;
                if (kind == 'S')
                {
                    // second operand must be integer shift count
                    if (type2 != TypeCode.Int32)
                    {
                        ok = false;
                    }
                }
                else
                {
                    // logical and arithmetic operands must be same type
                    if (type1 != type2)
                    {
                        if (kind == 'A' && type1 == TypeCode.Int64 && type2 == TypeCode.Int32)
                        {
                            // special case:  convert the second operand to Int64
                            code.NewInstruction(0x85 /* i2l */, null, null);
                            code.StackMap.PushStack(JavaType.LongType);
                            code.StackMap.PushStack(JavaType.LongType);
                            code.StackMap.PopStack(CilMain.Where);
                            code.StackMap.PopStack(CilMain.Where);
                        }
                        else if (kind == 'A' && type1 == TypeCode.Int32 && type2 == TypeCode.Int64)
                        {
                            // special case:  convert the second operand to Int32
                            code.NewInstruction(0x88 /* l2i */, null, null);
                        }
                        else
                        {
                            ok = false;
                        }
                    }

                    if (kind == 'L')
                    {
                        // logical operation requires integer operands
                        if (type1 != TypeCode.Int32 && type1 != TypeCode.Int64)
                        {
                            ok = false;
                        }
                    }
                }

                if (!ok)
                {
                    throw new Exception($"unexpected opcode or operands ({type1} and {type2})");
                }

                if (kind == 'A' && op == 0)
                {
                    OverflowArithmetic(code, type1, cilOp);
                    return;
                }

                if (kind == 'U')
                {
                    UnsignedDivide(code, type1, (cilOp == Code.Rem_Un));
                    return;
                }
            }

            if (type1 == TypeCode.Int64)
            {
                op++;       // ixxx -> lxxx
            }
            else if (type1 == TypeCode.Single)
            {
                op += 2;    // ixxx -> fxxx
            }
            else if (type1 == TypeCode.Double)
            {
                op += 3;    // ixxx -> dxxx
            }
            code.NewInstruction(op, null, null);
            code.StackMap.PushStack(CilType.From(new JavaType(type1, 0, null)));
        }
Example #25
0
        public void New(CilType elemType, int numDims, bool arrayTypeOnStack = false)
        {
            var elemTypeForArray = elemType.IsGenericParameter
                                 ? CilType.From(JavaType.ObjectType) : elemType;
            var arrayType = elemTypeForArray.AdjustRank(numDims);

            if (elemType.IsGenericParameter)
            {
                /*if (numDims != 1)
                 *  throw new Exception("unsupported number of dimensions in generic array");*/

                if (!arrayTypeOnStack)
                {
                    GenericUtil.LoadMaybeGeneric(elemType, code);
                }

                var parameters = new List <JavaFieldRef>();
                for (int i = 0; i < numDims; i++)
                {
                    parameters.Add(new JavaFieldRef("", JavaType.IntegerType));
                }
                parameters.Add(new JavaFieldRef("", CilType.SystemTypeType));

                code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType,
                                    new JavaMethodRef("New", JavaType.ObjectType, parameters));

                stackMap.PopStack(CilMain.Where);   // type

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

                arrayType = GenericArrayType;
            }

            else if (elemType.IsReference || numDims > 1)
            {
                if (numDims == 1)
                {
                    code.NewInstruction(0xBD /* anewarray */, elemType, null);
                }
                else
                {
                    code.NewInstruction(0xC5 /* multianewarray */, arrayType, numDims);
                }

                for (int i = 0; i < numDims; i++)
                {
                    stackMap.PopStack(CilMain.Where);
                }

                stackMap.PushStack(arrayType);  // arrayObj

                if (elemType.IsValueClass)
                {
                    code.NewInstruction(0x59 /* dup */, null, null);
                    stackMap.PushStack(arrayType);      // arrayCopy

                    if (elemType.HasGenericParameters)
                    {
                        // array of a value class ArrayElement<T>, pass this type
                        // as the second parameter to system.Array.Initialize

                        GenericUtil.LoadMaybeGeneric(elemType, code);

                        // third parameter is null
                        code.NewInstruction(0x01 /* aconst_null */, null, null);
                        stackMap.PushStack(JavaType.ObjectType);
                    }
                    else
                    {
                        // array of a plain value class, pass a constructed object
                        // as the third parameter to system.Array.Initialize

                        // second parameter is null
                        code.NewInstruction(0x01 /* aconst_null */, null, null);
                        stackMap.PushStack(CilType.SystemTypeType);

                        // model parameter is a new object
                        code.NewInstruction(0xBB /* new */, elemType.AsWritableClass, null);
                        stackMap.PushStack(elemType);
                        code.NewInstruction(0x59 /* dup */, null, null);
                        stackMap.PushStack(elemType);
                        code.NewInstruction(0xB7 /* invokespecial */, elemType.AsWritableClass,
                                            new CilMethod(elemType));
                        stackMap.PopStack(CilMain.Where);
                    }

                    code.NewInstruction(0x12 /* ldc */, null, numDims);
                    stackMap.PushStack(JavaType.IntegerType);

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

                    stackMap.PopStack(CilMain.Where);   // numDims
                    stackMap.PopStack(CilMain.Where);   // elemType
                    stackMap.PopStack(CilMain.Where);   // arrayType
                    stackMap.PopStack(CilMain.Where);   // arrayCopy
                }

                stackMap.PopStack(CilMain.Where);   // arrayObj
            }
            else
            {
                code.NewInstruction(0xBC /* newarray */, null, elemType.NewArrayType);

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

            stackMap.PushStack(arrayType);
        }
Example #26
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();
                    }
                }
            }
        }
Example #27
0
        void LoadConstant(Code op, object data)
        {
            JavaType pushType;
            object   pushValue;
            byte     pushOpcode;

            if (op == Code.Ldnull)
            {
                pushValue  = null;
                pushOpcode = 0x01; // aconst_null
                pushType   = JavaStackMap.Null;
            }
            else
            {
                pushOpcode = 0x12;            // ldc

                if (data is string stringVal) // Code.Ldstr
                {
                    pushValue = stringVal;
                    pushType  = JavaType.StringType;
                }
                else if (data is double doubleVal) // Code.Ldc_R8
                {
                    pushValue = doubleVal;
                    pushType  = JavaType.DoubleType;
                }
                else if (data is float floatVal) // Code.Ldc_R4
                {
                    pushValue = floatVal;
                    pushType  = JavaType.FloatType;
                }
                else if (data is long longVal) // Code.Ldc_I8
                {
                    pushValue = longVal;
                    pushType  = JavaType.LongType;
                }
                else
                {
                    pushType = JavaType.IntegerType;

                    if (data is int intVal) // Code.Ldc_I4
                    {
                        pushValue = intVal;
                    }

                    else if (data is sbyte sbyteVal) // Code.Ldc_I4_S
                    {
                        pushValue = (int)sbyteVal;
                    }

                    else if (op >= Code.Ldc_I4_M1 && op <= Code.Ldc_I4_8)
                    {
                        pushValue = (int)(op - Code.Ldc_I4_0);
                    }

                    else
                    {
                        throw new InvalidProgramException();
                    }
                }
            }

            code.NewInstruction(pushOpcode, null, pushValue);
            stackMap.PushStack(CilType.From(pushType));
        }
Example #28
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();
        }
Example #29
0
        public static void CreateSuppressibleFinalize(JavaMethod innerMethod, CilType declType,
                                                      JavaClass theClass)
        {
            //
            // if the class defines a finalizer method Finalize() then:
            //
            // - create a flag field that tracks whether finalization is suppressed
            //
            // - implement interface system.GC.FinalizeSuppressible, and its Set()
            // method, which sets the flag field
            //
            // - create a wrapper method that checks the flag field and possibly
            // invokes the original finalizer
            //
            // see also: system.GC in baselib
            //

            var flagField = new JavaField();

            flagField.Name  = "-finalize-suppressed";
            flagField.Type  = CilType.From(JavaType.BooleanType);
            flagField.Class = theClass;
            flagField.Flags = JavaAccessFlags.ACC_PRIVATE | JavaAccessFlags.ACC_VOLATILE;

            if (theClass.Fields == null)
            {
                theClass.Fields = new List <JavaField>();
            }
            theClass.Fields.Add(flagField);

            //
            // implement the interface method
            //

            var ifcMethod = new JavaMethod("system-GC$SuppressibleFinalize-Set",
                                           JavaType.VoidType);

            ifcMethod.Class = theClass;
            ifcMethod.Flags = JavaAccessFlags.ACC_PUBLIC;

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

            code.Method       = ifcMethod;
            code.Instructions = new List <JavaCode.Instruction>();
            code.MaxLocals    = code.MaxStack = 2;

            code.NewInstruction(0x19 /* aload */, null, (int)0);
            code.NewInstruction(0x12 /* ldc */, null, (int)1);
            code.NewInstruction(0xB5 /* putfield */, declType, flagField);
            code.NewInstruction(JavaType.VoidType.ReturnOpcode, null, null);

            theClass.Methods.Add(ifcMethod);
            theClass.AddInterface("system.GC$SuppressibleFinalize");

            //
            // create the wrapper method
            //

            var outerMethod = new JavaMethod(theClass, innerMethod);

            outerMethod.Flags = JavaAccessFlags.ACC_PROTECTED;
            innerMethod.Flags = JavaAccessFlags.ACC_PRIVATE;

            innerMethod.Name += "---inner";

            // prepare to generate instructions

            code              = outerMethod.Code = new JavaCode();
            code.Method       = outerMethod;
            code.Instructions = new List <JavaCode.Instruction>();
            code.StackMap     = new JavaStackMap();
            code.StackMap.SaveFrame((ushort)0, false, CilMain.Where);
            code.MaxLocals = code.MaxStack = 1;

            //
            // check the flag field to determine if suppressed
            //

            code.NewInstruction(0x19 /* aload */, null, (int)0);

            code.NewInstruction(0xB4 /* getfield */, declType, flagField);

            code.NewInstruction(0x9A /* ifne != zero */, null, (ushort)0xFFFE);

            code.NewInstruction(0x19 /* aload */, null, (int)0);

            code.NewInstruction(0xB7 /* invokespecial */, declType, innerMethod);

            code.NewInstruction(JavaType.VoidType.ReturnOpcode, null, null,
                                /* label */ 0xFFFE);

            code.StackMap.SaveFrame((ushort)0xFFFE, true, CilMain.Where);

            theClass.Methods.Add(outerMethod);
        }
Example #30
0
        int InitLocalsArgs(CilMethod myMethod, List <CilType> localTypes)
        {
            var     parameters = myMethod.WithGenericParameters.Parameters;
            int     numArgs    = parameters.Count;
            CilType thisType;

            if (myMethod.HasThisArg)
            {
                if (myMethod.IsConstructor)
                {
                    thisType = CilType.From(JavaStackMap.UninitializedThis);
                }
                else
                {
                    thisType = myMethod.DeclType;
                    if (thisType.IsValueClass)
                    {
                        thisType = thisType.MakeByRef();
                    }
                }
                stackMap.SetLocal(0, thisType);
                numArgs++;
            }
            else
            {
                thisType = null;
            }

            argToLocalMap = new int[numArgs];
            int nextArg   = 0;
            int nextIndex = 0;

            if (thisType != null)
            {
                argToLocalMap[nextArg++] = nextIndex++;
                localTypes.Add(thisType);
                numArgs--;
            }

            for (int i = 0; i < numArgs; i++)
            {
                var argType = (CilType)parameters[i].Type;
                stackMap.SetLocal(nextIndex, argType);

                var genericType = argType.GetMethodGenericParameter();
                if (genericType != null)
                {
                    if (genericType.IsArray && genericType.IsGenericParameter)
                    {
                        // note that GenericArrayType is compared by reference
                        // in CodeArrays, to detect an array of a generic type T[]
                        argType = CodeArrays.GenericArrayType;
                    }
                    else
                    {
                        argType = genericType;
                    }
                }

                argToLocalMap[nextArg++] = nextIndex;
                nextIndex += argType.Category;

                localTypes.Add(argType);
                while (nextIndex > localTypes.Count)
                {
                    localTypes.Add(null);
                }
            }

            return(nextIndex);
        }