예제 #1
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 ((!dataType.IsReference) &&
                    intoType is BoxedType intoBoxedType &&
                    dataType.PrimitiveType == intoBoxedType.UnboxedType.PrimitiveType)
                {
                    // 'stobj primitive' with a primitive value on the stack
                    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();
            }
        }
예제 #2
0
        void Store(CilType elemType)
        {
            stackMap.PopStack(CilMain.Where);                                // value
            stackMap.PopStack(CilMain.Where);                                // index
            var arrayType     = stackMap.PopStack(CilMain.Where) as CilType; // array
            var arrayElemType = arrayType.AdjustRank(-arrayType.ArrayRank);

            if (elemType == null)
            {
                elemType = arrayElemType;
            }

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

            if (object.ReferenceEquals(arrayType, GenericArrayType))
            {
                // stelem.any T into generic array T[]
                code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType, StoreArrayMethod);
            }
            else if (arrayElemType.IsValueClass && elemType.IsValueClass)
            {
                // storing a value type into an array of value types.
                // we use ValueType.ValueCopy to write over the element.

                int localIndex = locals.GetTempIndex(elemType);
                code.NewInstruction(elemType.StoreOpcode, null, localIndex);

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

                code.NewInstruction(elemType.LoadOpcode, null, localIndex);
                locals.FreeTempIndex(localIndex);

                // we can pass any type that is not a generic parameter
                GenericUtil.ValueCopy(CilType.SystemTypeType, code, true);
            }
            else if (arrayType.ArrayRank > 1)
            {
                // always 'aastore' if multidimensional array
                code.NewInstruction(arrayType.StoreArrayOpcode, null, null);
            }
            else
            {
                if (elemType.PrimitiveType == TypeCode.Int16 &&
                    (arrayType.PrimitiveType == TypeCode.Char ||
                     arrayType.PrimitiveType == TypeCode.UInt16))
                {
                    // stelem.i2 with a char[] array, should be 'castore' not 'sastore'
                    elemType = arrayType.AdjustRank(-arrayType.ArrayRank);
                }

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

                code.NewInstruction(elemType.StoreArrayOpcode, null, null);
            }
        }
예제 #3
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);
        }
예제 #4
0
        bool StoreFieldValue(string fldName, CilType fldType, CilType fldClass,
                             bool isStatic, bool isVolatile)
        {
            //
            // we generate a sequence of instructions based on the combination of
            //      isStatic, isGeneric, isBoxed, isCopyable
            //
            // isStatic=1 IsGeneric=1 IsBoxed=1 IsCopyable=X:
            //   [VAL] -> LoadST -> [VAL] [ST] -> getfield -> [VAL] [BOX] -> BoxedType.SetVO
            //
            // isStatic=1 IsGeneric=1 IsBoxed=0 IsCopyable=1:
            //   [VAL] -> LoadST -> [VAL] [ST] -> getfield -> [VAL] [OBJ] -> ValueType.Copy
            //
            // isStatic=1 IsGeneric=1 IsBoxed=0 IsCopyable=0:
            // * [VAL] -> LoadST -> [VAL] [ST] -> swap -> [ST] [VAL] -> putfield
            //
            // isStatic=1 IsGeneric=0 IsBoxed=1 IsCopyable=X:
            //   [VAL] -> getstatic -> [VAL] [BOX] -> BoxedType.SetVO
            //
            // isStatic=1 IsGeneric=0 IsBoxed=0 IsCopyable=1:
            //   [VAL] -> getstatic -> [VAL] [OBJ] -> ValueType.Copy
            //
            // isStatic=1 IsGeneric=0 IsBoxed=0 IsCopyable=0:
            //   [VAL] -> putstatic
            //
            // isStatic=0 IsGeneric=X IsBoxed=1 IsCopyable=X:
            // * [INS] [VAL] -> swap -> [VAL] [INS] -> getfield -> [VAL] [BOX] -> BoxedType.SetOV
            //
            // isStatic=0 IsGeneric=X IsBoxed=0 IsCopyable=1:
            //   [INS] [VAL] -> swap -> [VAL] [INS] -> getfield -> [VAL] [OBJ] -> ValueType.Copy
            //
            // isStatic=0 IsGeneric=X IsBoxed=0 IsCopyable=0:
            //   [INS] [VAL] -> putfield
            //
            // the combinations marked with an asterisk require swapping operands,
            // which is handled more effectively by first popping the value operand
            //

            var  fldRef  = new JavaFieldRef(fldName, fldType);
            bool isBoxed = fldType is BoxedType;

            if (isStatic)
            {
                if (fldClass.HasGenericParameters)
                {
                    // isStatic=1 IsGeneric=1 IsBoxed=1 IsCopyable=X
                    // isStatic=1 IsGeneric=1 IsBoxed=0 IsCopyable=1
                    // isStatic=1 IsGeneric=1 IsBoxed=0 IsCopyable=0
                    StoreStaticGeneric(fldClass, fldType, fldRef, isVolatile);
                }
                else
                {
                    // isStatic=1 IsGeneric=0 IsBoxed=1 IsCopyable=X
                    // isStatic=1 IsGeneric=0 IsBoxed=0 IsCopyable=1
                    // isStatic=1 IsGeneric=0 IsBoxed=0 IsCopyable=0
                    StoreStaticRegular(fldClass, fldType, fldRef, isVolatile);
                }
            }
            else
            {
                // isStatic=0 IsGeneric=X IsBoxed=1 IsCopyable=X
                // isStatic=0 IsGeneric=X IsBoxed=0 IsCopyable=1
                // isStatic=0 IsGeneric=X IsBoxed=0 IsCopyable=0
                StoreInstance(fldClass, fldType, fldRef, isVolatile);
            }

            return(true);



            void StoreStaticGeneric(CilType fldClass, CilType fldType, JavaFieldRef fldRef,
                                    bool isVolatile)
            {
                // isStatic=1 IsGeneric=1 IsBoxed=1 IsCopyable=X:
                //   [VAL] -> LoadST -> [VAL] [ST] -> getfield -> [VAL] [BOX] -> BoxedType.SetVO
                //
                // isStatic=1 IsGeneric=1 IsBoxed=0 IsCopyable=1:
                //   [VAL] -> LoadST -> [VAL] [ST] -> getfield -> [VAL] [OBJ] -> ValueType.Copy
                //
                // isStatic=1 IsGeneric=1 IsBoxed=0 IsCopyable=0:
                // * [VAL] -> LoadST -> [VAL] [ST] -> swap -> [ST] [VAL] -> putfield

                if (fldType.IsValueClass)
                {
                    fldClass = LoadStaticData(fldClass);

                    code.NewInstruction(0xB4 /* getfield */, fldClass.AsWritableClass, fldRef);

                    if (fldType is BoxedType boxedType && (!boxedType.IsBoxedIntPtr))
                    {
                        boxedType.SetValueVO(code, isVolatile);
                    }
                    else
                    {
                        GenericUtil.ValueCopy(fldType, code);
                    }
                }
예제 #5
0
        void Store(CilType elemType, Mono.Cecil.Cil.Instruction inst)
        {
            stackMap.PopStack(CilMain.Where);                                // value
            stackMap.PopStack(CilMain.Where);                                // index
            var arrayType     = stackMap.PopStack(CilMain.Where) as CilType; // array
            var arrayElemType = arrayType.AdjustRank(-arrayType.ArrayRank);

            if (elemType == null)
            {
                elemType = arrayElemType;
            }

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

            if (object.ReferenceEquals(arrayType, GenericArrayType))
            {
                // stelem.any T into generic array T[]
                code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType, StoreArrayMethod);
            }
            else if (arrayElemType.IsValueClass && elemType.IsValueClass)
            {
                // storing a value type into an array of value types.
                // we use ValueType.ValueCopy to write over the element.

                int localIndex = locals.GetTempIndex(elemType);
                code.NewInstruction(elemType.StoreOpcode, null, localIndex);

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

                code.NewInstruction(elemType.LoadOpcode, null, localIndex);
                locals.FreeTempIndex(localIndex);

                // we can pass any type that is not a generic parameter
                GenericUtil.ValueCopy(CilType.SystemTypeType, code, true);
            }
            else if (arrayType.ArrayRank > 1)
            {
                // always 'aastore' if multidimensional array
                code.NewInstruction(arrayType.StoreArrayOpcode, null, null);
            }
            else
            {
                if (elemType.PrimitiveType == TypeCode.Int16 &&
                    (arrayType.PrimitiveType == TypeCode.Char ||
                     arrayType.PrimitiveType == TypeCode.UInt16))
                {
                    // stelem.i2 with a char[] array, should be 'castore' not 'sastore'
                    elemType = arrayType.AdjustRank(-arrayType.ArrayRank);
                }
                else
                {
                    // Android AOT crashes the compilation if an immediate value
                    // is stored into a byte or short array, and the value does
                    // not fit within the range -128..127 or -32768..32767.
                    // simply checing if the previous instruction loaded the
                    // constant is not enough, because due to method inlining
                    // by the Android ART JIT, the immediate value might actually
                    // originate in a calling method.
                    // so we always force the value into range using i2b/i2s.
                    // see also: CodeNumber::ConvertToInteger

                    if (arrayType.PrimitiveType == TypeCode.Boolean ||
                        arrayType.PrimitiveType == TypeCode.SByte ||
                        arrayType.PrimitiveType == TypeCode.Byte)
                    {
                        code.NewInstruction(0x91 /* i2b */, null, null);
                    }
                    else if (arrayType.PrimitiveType == TypeCode.Int16)
                    {
                        code.NewInstruction(0x93 /* i2s */, null, null);
                    }
                }

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

                code.NewInstruction(elemType.StoreArrayOpcode, null, null);
            }
        }