Example #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);
                }
            }
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);

                    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);
        }
Example #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);
        }
Example #4
0
        void Process(int numCastableInterfaces)
        {
            code = newMethod.Code = new JavaCode(newMethod);
            var oldLabel = code.SetLabel(0xFFFF);

            locals     = new CodeLocals(method, defMethod, code);
            arrays     = new CodeArrays(code, locals);
            exceptions = new CodeExceptions(defMethodBody, code, locals);

            InsertMethodInitCode(numCastableInterfaces);

            code.SetLabel(oldLabel);

            stackMap = code.StackMap;
            stackMap.SaveFrame(0, false, CilMain.Where);

            ProcessInstructions();

            (code.MaxLocals, code.MaxStack) = locals.GetMaxLocalsAndStack();
            locals.TrackUnconditionalBranch(null);
        }
Example #5
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);
        }