Beispiel #1
0
 void SaveExceptionObject(TryClause tryClause, bool keepOnStack = true)
 {
     if (keepOnStack)
     {
         stackMap.PushStack(ThrowableType);
         code.NewInstruction(0x59 /* dup */, null, null);
     }
     tryClause.localIndex = locals.GetTempIndex(ThrowableType);
     code.NewInstruction(0x3A /* astore */, null, tryClause.localIndex);
     stackMap.PopStack(CilMain.Where);
 }
Beispiel #2
0
        public static void Instance(JavaCode code, CodeLocals locals, Mono.Cecil.Cil.Instruction cilInst)
        {
            if (cilInst.Operand is TypeReference cilType && cilInst.Next != null)
            {
                var stackTop = (CilType)code.StackMap.PopStack(CilMain.Where);
                if (!stackTop.IsReference)
                {
                    throw new InvalidProgramException(); // top of stack is a primitive type
                }
                var      castType  = (CilType)CilType.From(cilType);
                JavaType castClass = CilType.From(cilType).AsWritableClass;

                if (GenericUtil.ShouldCallGenericCast(stackTop, castType) ||
                    castType.IsGenericParameter)
                {
                    code.StackMap.PushStack(stackTop);
                    // casting to a generic type is done via GenericType.TestCast
                    GenericUtil.CastToGenericType(cilType, 0, code);
                    code.StackMap.PopStack(CilMain.Where);  // stackTop
                    if (!castType.IsGenericParameter)
                    {
                        code.NewInstruction(0xC0 /* checkcast */, castClass, null);
                    }
                    code.StackMap.PushStack(castClass);
                }

                else if (CodeArrays.CheckCast(castType, false, code))
                {
                    // if casting to Object[], ValueType[], to an array of
                    // interface type, or to an array of a generic parameter,
                    // then CodeArrays.CheckCast already generated a call to
                    // system.Array.CheckCast in baselib, and we are done here

                    if (!castType.IsGenericParameter)
                    {
                        // avoid cast since T[] might be a primitive array
                        code.NewInstruction(0xC0 /* checkcast */, castClass, null);
                    }
                    code.StackMap.PushStack(castClass);
                }

                //
                // the cil 'isinst' casts the operand to the requested class,
                // but the jvm 'instanceof' only returns zero or one.  so we
                // also use 'checkcast' to get the jvm to acknowledge the cast
                //
                // however, if the cil 'isinst' is immediately followed by
                // 'brtrue' or 'brfalse' then we don't have to actually cast
                //

                else if (!TestForBranch(code, castClass, cilInst.Next))
                {
                    ushort nextLabel  = (ushort)cilInst.Next.Offset;
                    int    localIndex = locals.GetTempIndex(stackTop);

                    TestAndCast(code, castClass, stackTop, nextLabel, localIndex);

                    locals.FreeTempIndex(localIndex);
                }
            }
Beispiel #3
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);
            }
        }
Beispiel #4
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);
            }
        }