Beispiel #1
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);
        }
Beispiel #2
0
        public static void LoadMaybeGeneric(CilType loadType, JavaCode code)
        {
            if (loadType.IsGenericParameter)
            {
                LoadGeneric(loadType.JavaName, code);
            }
            else
            {
                // all GetType variants take a first parameter of type java.lang.Class
                List <JavaFieldRef> parameters = new List <JavaFieldRef>();
                parameters.Add(new JavaFieldRef("", JavaType.ClassType));

                int arrayRank = loadType.ArrayRank;
                if (arrayRank == 0 || (!loadType.IsGenericParameter))
                {
                    code.NewInstruction(0x12 /* ldc */, loadType.AsWritableClass, null);
                }
                else
                {
                    // for a generic type T[], we want to load just the element T,
                    // and then (see below) call MakeArrayType on the result
                    var loadTypeElem = loadType.AdjustRank(-arrayRank);
                    code.NewInstruction(0x12 /* ldc */, loadTypeElem.AsWritableClass, null);
                }
                code.StackMap.PushStack(JavaType.ClassType);

                if (loadType.HasGenericParameters)
                {
                    LoadGenericInstance(loadType, parameters, code);
                }

                code.NewInstruction(0xB8 /* invokestatic */, CilType.SystemRuntimeTypeType,
                                    new JavaMethodRef("GetType", CilType.SystemTypeType, parameters));

                for (int i = 0; i < parameters.Count; i++)
                {
                    code.StackMap.PopStack(CilMain.Where);
                }

                code.StackMap.PushStack(CilType.SystemTypeType);

                if (arrayRank != 0 && loadType.IsGenericParameter)
                {
                    code.NewInstruction(0x12 /* ldc */, null, (int)arrayRank);
                    code.StackMap.PushStack(JavaType.IntegerType);

                    code.NewInstruction(0xB6 /* invokevirtual */, CilType.SystemTypeType,
                                        new JavaMethodRef("MakeArrayType",
                                                          CilType.SystemTypeType, JavaType.IntegerType));

                    code.StackMap.PopStack(CilMain.Where);
                }
            }
        }
Beispiel #3
0
        public void Address(CilType arrayType)
        {
            stackMap.PopStack(CilMain.Where);       // index

            if (arrayType == null)
            {
                arrayType = (CilType)stackMap.PopStack(CilMain.Where);
            }
            else
            {
                stackMap.PopStack(CilMain.Where);   // array
            }
            var elemType = arrayType.AdjustRank(-arrayType.ArrayRank);

            if (elemType.IsReference)
            {
                if (elemType.IsGenericParameter)
                {
                    // call system.Array.Box(object array, int index)
                    code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType,
                                        new JavaMethodRef("Box", CilType.SystemValueType,
                                                          JavaType.ObjectType, JavaType.IntegerType));
                }
                else if (elemType.IsValueClass)
                {
                    code.NewInstruction(0x32 /* aaload */, null, null);
                }
                else
                {
                    // call system.Reference.Box(object a, int i)
                    elemType = new BoxedType(elemType, false);
                    code.NewInstruction(0xB8 /* invokestatic */, elemType,
                                        new JavaMethodRef("Box", elemType,
                                                          JavaType.ObjectType, JavaType.IntegerType));
                }
                stackMap.PushStack(elemType);
            }
            else
            {
                // call system.(PrimitiveType).Box(primitiveType[] a, int i)
                var typeCode = elemType.PrimitiveType;

                stackMap.PushStack(new BoxedType(elemType, false));

                arrayType = elemType.AdjustRank(1);
                elemType  = elemType.AsWritableClass;
                code.NewInstruction(0xB8 /* invokestatic */, elemType,
                                    new JavaMethodRef("Box", elemType, arrayType, JavaType.IntegerType));
            }
        }
Beispiel #4
0
        void Load(CilType arrayType, CilType elemType, Mono.Cecil.Cil.Instruction inst)
        {
            if (arrayType == null)
            {
                arrayType = elemType.AdjustRank(1);
            }

            /*Console.WriteLine("(LOAD) ARRAY TYPE = " + arrayType + "," + arrayType.ArrayRank
             + " ELEM TYPE = " + elemType + "," + elemType.ArrayRank
             + " ELEMVAL? " + elemType.IsValueClass
             + " ELEMGEN? " + elemType.IsGenericParameter);*/

            if (object.ReferenceEquals(arrayType, GenericArrayType) ||
                elemType.IsGenericParameter || arrayType.IsGenericParameter)
            {
                code.NewInstruction(0xB8 /* invokestatic */,
                                    SystemArrayType, LoadArrayMethod);
                if (elemType.ArrayRank != 0)
                {
                    elemType = GenericArrayType;
                }
            }
            else
            {
                if (elemType.PrimitiveType == TypeCode.Int16 &&
                    (arrayType.PrimitiveType == TypeCode.Char ||
                     arrayType.PrimitiveType == TypeCode.UInt16))
                {
                    // ldelem.i2 with a char[] array, should be 'caload' not 'saload'
                    elemType = arrayType.AdjustRank(-arrayType.ArrayRank);
                }

                code.NewInstruction(elemType.LoadArrayOpcode, null, null);

                if (arrayType.IsValueClass || elemType.IsValueClass)
                {
                    CilMethod.ValueMethod(CilMethod.ValueClone, code);
                }
            }

            stackMap.PushStack(elemType);
        }
Beispiel #5
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);
        }
Beispiel #6
0
        public void Address(CilType arrayType, Mono.Cecil.Cil.Instruction inst)
        {
            stackMap.PopStack(CilMain.Where);       // index

            if (arrayType == null)
            {
                arrayType = (CilType)stackMap.PopStack(CilMain.Where);
            }
            else
            {
                stackMap.PopStack(CilMain.Where);   // array
            }
            var elemType = arrayType.AdjustRank(-arrayType.ArrayRank);

            if (inst != null && inst.Next != null)
            {
                var(spanType, _) = locals.GetLocalFromStoreInst(
                    inst.Next.OpCode.Code, inst.Next.Operand);

                if (CodeSpan.AddressArray(elemType, spanType, code))
                {
                    return;
                }
            }

            if (elemType.IsReference)
            {
                if (elemType.IsGenericParameter)
                {
                    // call system.Array.Box(object array, int index)
                    code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType,
                                        new JavaMethodRef("Box", CilType.SystemValueType,
                                                          JavaType.ObjectType, JavaType.IntegerType));
                }
                else if (elemType.IsValueClass)
                {
                    code.NewInstruction(0x32 /* aaload */, null, null);
                }
                else
                {
                    // call system.Reference.Box(object a, int i)
                    elemType = new BoxedType(elemType, false);
                    code.NewInstruction(0xB8 /* invokestatic */, elemType,
                                        new JavaMethodRef("Box", elemType,
                                                          JavaType.ObjectType, JavaType.IntegerType));
                }
                stackMap.PushStack(elemType);
            }
            else
            {
                // call system.(PrimitiveType).Box(primitiveType[] a, int i)
                var typeCode = elemType.PrimitiveType;

                stackMap.PushStack(new BoxedType(elemType, false));

                arrayType = elemType.AdjustRank(1);
                elemType  = elemType.AsWritableClass;
                code.NewInstruction(0xB8 /* invokestatic */, elemType,
                                    new JavaMethodRef("Box", elemType, arrayType, JavaType.IntegerType));
            }
        }
Beispiel #7
0
        void Load(CilType arrayType, CilType elemType, Mono.Cecil.Cil.Instruction inst)
        {
            if (arrayType == null)
            {
                arrayType = elemType.AdjustRank(1);
            }

            /*Console.WriteLine("(LOAD) ARRAY TYPE = " + arrayType + "," + arrayType.ArrayRank
             + " ELEM TYPE = " + elemType + "," + elemType.ArrayRank
             + " ELEMVAL? " + elemType.IsValueClass
             + " ELEMGEN? " + elemType.IsGenericParameter);*/

            if (object.ReferenceEquals(arrayType, GenericArrayType) ||
                elemType.IsGenericParameter || arrayType.IsGenericParameter)
            {
                code.NewInstruction(0xB8 /* invokestatic */,
                                    SystemArrayType, LoadArrayMethod);
                if (elemType.ArrayRank != 0)
                {
                    elemType = GenericArrayType;
                }
            }
            else
            {
                if (elemType.PrimitiveType == TypeCode.Int16 &&
                    (arrayType.PrimitiveType == TypeCode.Char ||
                     arrayType.PrimitiveType == TypeCode.UInt16))
                {
                    // ldelem.i2 with a char[] array, should be 'caload' not 'saload'
                    elemType = arrayType.AdjustRank(-arrayType.ArrayRank);
                }

                code.NewInstruction(elemType.LoadArrayOpcode, null, null);

                if (elemType.PrimitiveType == TypeCode.Byte)
                {
                    // unsigned byte result should be truncated to 8-bits
                    // (unless already followed by "ldc.i4 255 ; and")
                    bool followedByAndWith255 =
                        CodeBuilder.IsLoadConstant(inst.Next) == 0xFF &&
                        inst.Next.Next?.OpCode.Code == Code.And;

                    if (!followedByAndWith255)
                    {
                        stackMap.PushStack(JavaType.IntegerType);
                        code.NewInstruction(0x12 /* ldc */, null, (int)0xFF);
                        code.NewInstruction(0x7E /* iand */, null, null);
                        stackMap.PopStack(CilMain.Where);
                    }
                }

                if (arrayType.IsValueClass || elemType.IsValueClass)
                {
                    CilMethod.ValueMethod(CilMethod.ValueClone, code);
                    if (elemType.IsValueClass)
                    {
                        code.NewInstruction(0xC0 /* checkcast */, elemType, null);
                    }
                }
            }

            stackMap.PushStack(elemType);
        }