예제 #1
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);
                }
            }
예제 #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);

                    if (srcType.ArrayRank != 0 &&
                        srcType.ArrayRank == dstType.ArrayRank &&
                        srcType.PrimitiveType != 0 &&
                        dstType.PrimitiveType != 0 &&
                        srcType.AdjustRank(-srcType.ArrayRank).NewArrayType
                        == dstType.AdjustRank(-dstType.ArrayRank).NewArrayType)
                    {
                        // casting to same java array type, e.g. byte[] to sbyte[]
                        op = 0x00; // nop
                    }
                    else if (dstType.IsGenericParameter)
                    {
                        op = 0x00; // nop
                    }
                    else
                    {
                        op = 0xC0; // checkcast
                    }
                }
                else
                {
                    throw new InvalidProgramException();
                }
            }

            code.NewInstruction(op, dstType, null);
            code.StackMap.PushStack(dstType);
        }
예제 #3
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);
        }
예제 #4
0
        void ExceptionClauseSetup(ushort instOffset, CatchClause catchClause)
        {
            // if this is the first exception for the try block:
            //
            // the offset is recorded in the exception attribute, so we need
            // to generate a stack frame for it, which matches the stack frame
            // on entry to the try block, with a pushed java.lang.Throwable.

            var tryClause = catchClause.tryClause;

            if (catchClause == tryClause.catchClauses[0])
            {
                stackMap.LoadFrame((ushort)tryClause.tryStart, false, CilMain.Where);
                stackMap.PushStack(ThrowableType);
                stackMap.SaveFrame((ushort)instOffset, true, CilMain.Where);

                if (!catchClause.finallyClause)
                {
                    code.NewInstruction(0xB8 /* invokestatic */, CilType.SystemUtilType,
                                        new JavaMethodRef("TranslateException",
                                                          ThrowableType, ThrowableType));
                }
            }

            // if this is a finally clause, we have nothing further to do.
            // but if this is a filter clause, do some additional set up.

            if (catchClause.finallyClause)
            {
                if (catchClause.hasNestedTry)
                {
                    // see also:  ScanCatchClauseForNestedTry
                    SaveExceptionObject(tryClause, false);
                }

                if (catchClause.faultClause)
                {
                    // the 'fault' clause should start with a check whether
                    // an exception was thrown, which is very similar to what
                    // 'endfinally' does at the end of a normal 'finally' block,
                    // so we can reuse the same code.
                    Translate_Endfinally(instOffset, true);
                }

                return;
            }

            //
            // if this is a filter clause, we just need to initialize loals
            //

            if (catchClause.filterCondStart != 0)
            {
                // should the filter test pass, we need push the exception
                // object.  we don't know which local the filter test uses
                // to store the exception, so we make our own copy.  this
                // will be loaded by the 'endfilter' instruction, see there.

                SaveExceptionObject(tryClause);

                return;
            }

            //
            // for a non-filter catch clause that catches any kind of
            // exception, we don't need to test the exception type at all
            //

            if (catchClause.catchType.Equals(ThrowableType))
            {
                if (catchClause.includesRethrow)
                {
                    SaveExceptionObject(tryClause);
                }
            }

            //
            // otherwise, we do need to test the exception type, and
            // possibly branch to a secondary catch clause in the chain.
            //

            if (catchClause.catchFromType == null)
            {
                // exception type is plain type.  we will use follow up
                // instructions 'ifeq == zero' and 'ifne != zero',
                // see ExceptionClauseCommon

                if (catchClause.catchType.Equals(ThrowableType))
                {
                    code.NewInstruction(0x04 /* iconst_1 */, null, null);
                    stackMap.PushStack(JavaType.IntegerType);
                }
                else
                {
                    code.NewInstruction(0x59 /* dup */, null, null);
                    stackMap.PushStack(ThrowableType);
                    code.NewInstruction(0xC1 /* instanceof */, catchClause.catchType, null);
                }
            }
            else
            {
                // exception type is a generic type.  we will use follow up
                // instructions 'ifnull' and 'ifnonnnull'.
                // see also below in ExceptionClauseCommon
                code.NewInstruction(0x59 /* dup */, null, null);
                stackMap.PushStack(ThrowableType);
                GenericUtil.CastToGenericType(catchClause.catchFromType, 0, code);
            }

            stackMap.PopStack(CilMain.Where);

            ExceptionClauseCommon(catchClause);
        }