예제 #1
0
        void InitObject(object data)
        {
            if (data is TypeReference typeRef)
            {
                var dataType = CilType.From(typeRef);
                var fromType = code.StackMap.PopStack(CilMain.Where);

                if (CodeSpan.Clear(fromType, dataType, code))
                {
                    return;
                }

                if (dataType.IsGenericParameter ||
                    (dataType.IsValueClass && dataType.Equals(fromType)))
                {
                    if (dataType.IsGenericParameter)
                    {
                        code.NewInstruction(0xC0 /* checkcast */, CilType.SystemValueType, null);
                    }

                    code.NewInstruction(0xB6 /* invokevirtual */,
                                        CilType.SystemValueType, CilMethod.ValueClear);
                    return;
                }
            }
            throw new InvalidProgramException();
        }
예제 #2
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();
            }
        }
예제 #3
0
        static byte TestEq(JavaCode code, JavaType stackTop, JavaType stackTop2,
                           Mono.Cecil.Cil.Instruction cilInst)
        {
            if (stackTop.IsReference || stackTop2.IsReference)
            {
                byte cmpOp = CodeSpan.CompareEq(stackTop, stackTop2, cilInst, code);
                if (cmpOp == 0)
                {
                    cmpOp = 0xA5; // if_acmpeq (reference)
                }
                return(cmpOp);
            }

            if (stackTop2.IsIntLike && (stackTop.PrimitiveType == TypeCode.Int32 ||
                                        stackTop.PrimitiveType == TypeCode.UInt32 ||
                                        stackTop.PrimitiveType == TypeCode.Int16 ||
                                        stackTop.PrimitiveType == TypeCode.UInt16 ||
                                        stackTop.PrimitiveType == TypeCode.SByte ||
                                        stackTop.PrimitiveType == TypeCode.Byte ||
                                        stackTop.PrimitiveType == TypeCode.Char ||
                                        stackTop.PrimitiveType == TypeCode.Boolean))
            {
                return(0x9F); // if_icmpeq
            }

            byte op;

            if ((stackTop.PrimitiveType == TypeCode.Int64 ||
                 stackTop.PrimitiveType == TypeCode.UInt64) &&
                (stackTop2.PrimitiveType == TypeCode.Int64 ||
                 stackTop2.PrimitiveType == TypeCode.UInt64))
            {
                op = 0x94; // lcmp (long)
            }

            else if (stackTop.PrimitiveType == TypeCode.Single &&
                     stackTop2.PrimitiveType == TypeCode.Single)
            {
                op = 0x95; // fcmpl (float)
            }

            else if (stackTop.PrimitiveType == TypeCode.Double &&
                     stackTop2.PrimitiveType == TypeCode.Double)
            {
                op = 0x97; // dcmpl (double)
            }

            else
            {
                throw new Exception($"incompatible types '{stackTop}' and '{stackTop2}'");
            }

            code.NewInstruction(op, null, null);
            return(0x99); // ifeq == zero
        }
예제 #4
0
        void PopObjectAndLoadFromSpan(CilType fldClass)
        {
            var stackTop = stackMap.PopStack(CilMain.Where);

            stackMap.PushStack(stackTop);

            if (fldClass.IsValueClass &&
                CodeSpan.LoadStore(true, (CilType)stackTop, null, fldClass, code))
            {
                stackMap.PopStack(CilMain.Where);
                code.NewInstruction(0xC0 /* checkcast */, fldClass, null);
            }

            // pop object reference
            stackMap.PopStack(CilMain.Where);
        }
예제 #5
0
        void LoadObject(Code cilOp, object data)
        {
            if (data is TypeReference typeRef)
            {
                var dataType = CilType.From(typeRef);
                var fromType = (CilType)code.StackMap.PopStack(CilMain.Where);

                if (CodeSpan.LoadStore(true, fromType, null, dataType, code))
                {
                    return;
                }

                if ((!dataType.IsReference) && cilOp == Code.Ldobj &&
                    fromType is BoxedType fromBoxedType &&
                    dataType.PrimitiveType == fromBoxedType.UnboxedType.PrimitiveType)
                {
                    // 'ldobj primitive' with a corresponding boxed type on the stack.
                    // we implement by unboxing the boxed type into a primitive value.
                    fromBoxedType.GetValue(code);
                    stackMap.PushStack(fromBoxedType.UnboxedType);
                    return;
                }

                if (dataType.IsGenericParameter ||
                    (dataType.IsValueClass && dataType.Equals(fromType)))
                {
                    code.StackMap.PushStack(dataType);

                    if (SkipClone(cilInst.Next, fromType))
                    {
                        // see below for the several cases where we determine
                        // that we can safely avoid making a clone of the value
                        code.NewInstruction(0x00 /* nop */, null, null);
                    }
                    else if (dataType.IsGenericParameter)
                    {
                        GenericUtil.ValueClone(code);
                    }
                    else if (cilOp == Code.Ldobj)
                    {
                        code.NewInstruction(0x00 /* nop */, null, null);
                    }
                    else
                    {
                        CilMethod.ValueMethod(CilMethod.ValueClone, code);
                    }
                    return;
                }

                if (dataType.IsReference && cilOp == Code.Box)
                {
                    // 'box' is permitted on reference types, we treat it as a cast
                    code.StackMap.PushStack(fromType);
                    CastToClass(data);
                    return;
                }

                if (!dataType.IsReference)
                {
                    var boxedType = new BoxedType(dataType, false);
                    code.StackMap.PushStack(boxedType);
                    boxedType.BoxValue(code);
                    return;
                }
            }
            throw new InvalidProgramException();


            bool SkipClone(Mono.Cecil.Cil.Instruction next, CilType checkType)
            {
                if (checkType.IsByReference)
                {
                    return(true);
                }

                if (next == null)
                {
                    return(false);
                }
                var op = next.OpCode.Code;

                if (IsBrTrueBrFalseIsInst(op))
                {
                    // if 'ldobj' or 'box' is followed by a check for null,
                    // we don't actually need to clone just for the test
                    return(true);
                }

                if (op == Code.Box)
                {
                    if (next.Operand is TypeReference nextTypeRef)
                    {
                        // 'ldobj' may be followed by 'box', to load the value
                        // of a byref value type, and then box it into an object.
                        // effectively we only need to clone once, in such a case.
                        return(CilType.From(nextTypeRef).Equals(checkType));
                    }
                }

                var(storeType, _) = locals.GetLocalFromStoreInst(op, next.Operand);
                if (storeType != null)
                {
                    // 'ldobj' or 'box' may be followed by a store instruction.
                    // if storing into a variable of the same value type, the
                    // next instruction will copy the value, so skip clone.
                    return(storeType.Equals(checkType));
                }

                if (op == Code.Ret && checkType.IsClonedAtTop)
                {
                    // if the value on the stack was cloned/boxed at the top of
                    // the method, then we can avoid clone and return it directly.
                    // see also:  CilType.MakeClonedAtTop and its callers.
                    return(true);
                }

                if (op == Code.Unbox_Any)
                {
                    if (next.Operand is TypeReference nextTypeRef)
                    {
                        // 'ldobj' or 'box' may be followed by 'unbox' and
                        // then one of the instructions above, e.g. 'brtrue'
                        // or 'stloc'.  we still want to detect such a case
                        // and prevent a needless clone.
                        return(SkipClone(next.Next, CilType.From(nextTypeRef)));
                    }
                }

                return(false);
            }
        }
예제 #6
0
        void CallInstructionTranslator()
        {
            switch (cilOp)
            {
            case Code.Nop:
            case Code.Volatile:
            case Code.Constrained:
            case Code.Unaligned:
            case Code.Readonly:
            case Code.Tail:

                code.NewInstruction(0x00 /* nop */, null, null);
                break;

            case Code.Break:

                code.NewInstruction(0xCA /* debugger break */, null, null);
                break;

            case Code.Pop:
            case Code.Dup:

                PopOrDupStack(cilOp);
                break;

            case Code.Ldarg_0:
            case Code.Ldarg_1:
            case Code.Ldarg_2:
            case Code.Ldarg_3:
            case Code.Ldloc_0:
            case Code.Ldloc_1:
            case Code.Ldloc_2:
            case Code.Ldloc_3:
            case Code.Ldarg:
            case Code.Ldarg_S:
            case Code.Ldloc:
            case Code.Ldloc_S:

                locals.LoadValue(cilOp, cilInst.Operand);
                break;

            case Code.Stloc_0:
            case Code.Stloc_1:
            case Code.Stloc_2:
            case Code.Stloc_3:
            case Code.Starg:
            case Code.Starg_S:
            case Code.Stloc:
            case Code.Stloc_S:

                locals.StoreValue(cilOp, cilInst.Operand);
                break;

            case Code.Ldarga:
            case Code.Ldloca:
            case Code.Ldarga_S:
            case Code.Ldloca_S:

                locals.LoadAddress(cilInst.Operand);
                break;

            case Code.Ldc_I4_M1:
            case Code.Ldc_I4_0:
            case Code.Ldc_I4_1:
            case Code.Ldc_I4_2:
            case Code.Ldc_I4_3:
            case Code.Ldc_I4_4:
            case Code.Ldc_I4_5:
            case Code.Ldc_I4_6:
            case Code.Ldc_I4_7:
            case Code.Ldc_I4_8:
            case Code.Ldc_I4_S:
            case Code.Ldc_I4:
            case Code.Ldc_I8:
            case Code.Ldc_R4:
            case Code.Ldc_R8:
            case Code.Ldstr:
            case Code.Ldnull:

                LoadConstant(cilOp, cilInst);
                break;

            case Code.Ldfld:
            case Code.Ldflda:
            case Code.Stfld:
            case Code.Ldsfld:
            case Code.Ldsflda:
            case Code.Stsfld:

                LoadStoreField(cilOp, cilInst.Operand);
                break;

            case Code.Initobj:

                InitObject(cilInst.Operand);
                break;

            case Code.Newobj:
            case Code.Call:
            case Code.Callvirt:
            case Code.Ret:

                CallMethod(cilOp, cilInst.Operand);
                break;

            case Code.Castclass:

                CastToClass(cilInst.Operand);
                break;

            case Code.Ldtoken:

                LoadToken();
                break;

            case Code.Unbox:
            case Code.Unbox_Any:

                UnboxObject(cilOp, cilInst.Operand);
                break;

            case Code.Ldobj:
            case Code.Box:

                LoadObject(cilOp, cilInst.Operand);
                break;

            case Code.Stobj:

                StoreObject(cilInst.Operand);
                break;

            case Code.Br:
            case Code.Br_S:
            case Code.Brtrue:
            case Code.Brtrue_S:
            case Code.Beq:
            case Code.Beq_S:
            case Code.Bgt:
            case Code.Bgt_S:
            case Code.Bgt_Un:
            case Code.Bgt_Un_S:
            case Code.Blt:
            case Code.Blt_S:
            case Code.Blt_Un:
            case Code.Blt_Un_S:

                CodeCompare.Straight(code, cilOp, locals, cilInst);
                break;

            case Code.Brfalse:
            case Code.Brfalse_S:
            case Code.Bne_Un:
            case Code.Bne_Un_S:
            case Code.Ble:
            case Code.Ble_S:
            case Code.Ble_Un:
            case Code.Ble_Un_S:
            case Code.Bge:
            case Code.Bge_S:
            case Code.Bge_Un:
            case Code.Bge_Un_S:

                CodeCompare.Opposite(code, cilOp, locals, cilInst);
                break;

            case Code.Cgt:
            case Code.Cgt_Un:
            case Code.Ceq:
            case Code.Clt:
            case Code.Clt_Un:

                CodeCompare.Compare(code, cilOp, cilInst);
                break;

            case Code.Switch:

                CodeCompare.Switch(code, cilInst);
                break;

            case Code.Isinst:

                CodeCompare.Instance(code, locals, cilInst);
                break;

            case Code.Conv_I1:
            case Code.Conv_Ovf_I1:
            case Code.Conv_Ovf_I1_Un:
            case Code.Conv_I2:
            case Code.Conv_Ovf_I2:
            case Code.Conv_Ovf_U2_Un:
            case Code.Conv_I4:
            case Code.Conv_Ovf_I4:
            case Code.Conv_Ovf_I4_Un:
            case Code.Conv_I8:
            case Code.Conv_Ovf_I8:
            case Code.Conv_Ovf_I8_Un:
            case Code.Conv_U1:
            case Code.Conv_Ovf_U1:
            case Code.Conv_Ovf_U1_Un:
            case Code.Conv_U2:
            case Code.Conv_Ovf_U2:
            case Code.Conv_Ovf_I2_Un:
            case Code.Conv_U4:
            case Code.Conv_Ovf_U4:
            case Code.Conv_Ovf_U4_Un:
            case Code.Conv_U8:
            case Code.Conv_Ovf_U8:
            case Code.Conv_Ovf_U8_Un:
            case Code.Conv_I:
            case Code.Conv_Ovf_I:
            case Code.Conv_Ovf_I_Un:
            case Code.Conv_U:
            case Code.Conv_Ovf_U:
            case Code.Conv_Ovf_U_Un:
            case Code.Conv_R4:
            case Code.Conv_R8:
            case Code.Conv_R_Un:

                CodeNumber.Conversion(code, cilOp, cilInst);
                break;

            case Code.Add:
            case Code.Sub:
            case Code.Mul:
            case Code.Neg:
            case Code.Div:
            case Code.Div_Un:
            case Code.Rem:
            case Code.Rem_Un:
            case Code.And:
            case Code.Or:
            case Code.Xor:
            case Code.Not:
            case Code.Shl:
            case Code.Shr:
            case Code.Shr_Un:
            case Code.Add_Ovf:
            case Code.Add_Ovf_Un:
            case Code.Sub_Ovf:
            case Code.Sub_Ovf_Un:
            case Code.Mul_Ovf:
            case Code.Mul_Ovf_Un:

                CodeNumber.Calculation(code, cilOp, cilInst);
                break;

            case Code.Ldind_I1:
            case Code.Ldind_U1:
            case Code.Ldind_I2:
            case Code.Ldind_U2:
            case Code.Ldind_I4:
            case Code.Ldind_U4:
            case Code.Ldind_I8:
            case Code.Ldind_I:
            case Code.Ldind_R4:
            case Code.Ldind_R8:
            case Code.Ldind_Ref:
            case Code.Stind_I1:
            case Code.Stind_I2:
            case Code.Stind_I4:
            case Code.Stind_I8:
            case Code.Stind_I:
            case Code.Stind_R4:
            case Code.Stind_R8:
            case Code.Stind_Ref:

                CodeNumber.Indirection(code, cilOp);
                break;

            case Code.Throw:
            case Code.Rethrow:
            case Code.Leave:
            case Code.Leave_S:
            case Code.Endfinally:
            case Code.Endfilter:

                exceptions.Translate(cilInst);
                break;

            case Code.Newarr:

                arrays.New(cilInst.Operand);
                break;

            case Code.Ldlen:

                arrays.Length();
                break;

            case Code.Ldelema:

                arrays.Address(null, cilInst);
                break;

            case Code.Ldelem_I1:
            case Code.Ldelem_U1:
            case Code.Ldelem_I2:
            case Code.Ldelem_U2:
            case Code.Ldelem_I4:
            case Code.Ldelem_U4:
            case Code.Ldelem_I8:
            case Code.Ldelem_I:
            case Code.Ldelem_R4:
            case Code.Ldelem_R8:
            case Code.Ldelem_Ref:
            case Code.Ldelem_Any:

                arrays.Load(cilOp, cilInst.Operand, cilInst);
                break;

            case Code.Stelem_I1:
            case Code.Stelem_I2:
            case Code.Stelem_I4:
            case Code.Stelem_I8:
            case Code.Stelem_I:
            case Code.Stelem_R4:
            case Code.Stelem_R8:
            case Code.Stelem_Any:
            case Code.Stelem_Ref:

                arrays.Store(cilOp, cilInst);
                break;

            case Code.Ldftn:
            case Code.Ldvirtftn:

                Delegate.LoadFunction(code, cilInst);
                break;

            case Code.Sizeof:

                CodeSpan.Sizeof(cilInst.Operand, code);
                break;

            case Code.Localloc:

                CodeSpan.Localloc(code);
                break;

            /*  instructions not handled:
             *      Jmp, Calli, Cpobj, Refanyval, Ckfinite, Mkrefany, Arglist,
             *      Tail, Cpblk, Initblk, No, Refanytype, */

            default:
                throw new InvalidProgramException();
            }
        }
예제 #7
0
        static byte TestGtLt(JavaCode code, JavaType stackTop, JavaType stackTop2,
                             bool greater, bool unsigned_unordered)
        {
            byte op;

            //
            // for floating point, normal comparison returns 0 if either value
            // is NaN, while unordered comparison returns 1.  we have fcmp/dcmp
            // variants which return either 1 or -1.  following the comparison,
            // we have ifgt/iflt to check if the result is either greater than
            // or less than 0.  we consider all this when picking the opcode:
            //
            //                  test    normal compare  unordered compare
            //  greater than    ifgt        xcmpl              xcmpg
            //     less than    iflt        xcmpg              xcmpl
            //

            if (stackTop.PrimitiveType == TypeCode.Single)
            {
                op = (byte)((greater != unsigned_unordered) ? 0x95    // fcmpl
                                                             : 0x96); // fcmpg
            }

            else if (stackTop.PrimitiveType == TypeCode.Double)
            {
                op = (byte)((greater != unsigned_unordered) ? 0x97    // dcmpl
                                                             : 0x98); // dcmpg
            }

            //
            // for unsigned integer comparison, we use library function
            // system.UInt{32,64}.CompareTo, followed by ifgt/iflt
            //

            else if (unsigned_unordered && stackTop.PrimitiveType != TypeCode.Char)
            {
                char   typeChar;
                int    typeBits;
                string typeName = null;

                if (stackTop.PrimitiveType == TypeCode.SByte ||
                    stackTop.PrimitiveType == TypeCode.Byte)
                {
                    typeChar = 'B';
                    typeBits = 0;
                    typeName = "Byte";
                }
                else if (stackTop.PrimitiveType == TypeCode.Int16 ||
                         stackTop.PrimitiveType == TypeCode.UInt16)
                {
                    typeChar = 'S';
                    typeBits = 16;
                }
                else if (stackTop.PrimitiveType == TypeCode.Int32 ||
                         stackTop.PrimitiveType == TypeCode.UInt32)
                {
                    typeChar = 'I';
                    typeBits = 32;
                }
                else if (stackTop.PrimitiveType == TypeCode.Int64 ||
                         stackTop.PrimitiveType == TypeCode.UInt64)
                {
                    typeChar = 'J';
                    typeBits = 64;
                }
                else if (greater && stackTop.Equals(JavaStackMap.Null))
                {
                    // per MS CLI Partition III table 4 note 2, 'cgt.un'
                    // can be used to check for a non-null reference
                    return(0xA6); // if_acmpne
                }
                else
                {
                    if (CodeSpan.CompareGtLt(stackTop, stackTop2, code))
                    {
                        return((byte)(greater ? 0x9D     // ifgt
                                               : 0x9B)); // iflt
                    }

                    throw new InvalidProgramException();
                }

                if (typeBits != 0)
                {
                    typeName = "UInt" + typeBits.ToString();
                }

                code.NewInstruction(0xB8 /* invokestatic */,
                                    new JavaType(0, 0, $"system.{typeName}"),
                                    new JavaMethodRef("CompareTo",
                                                      $"({typeChar}{typeChar})I", CilMain.Where));

                /*
                 * new JavaType(0, 0, $"java.lang.{typeName}"),
                 * new JavaMethodRef("compareUnsigned",
                 *               $"({typeChar}{typeChar})I", CilMain.Where));*/
                op = 0;
            }

            //
            // for signed long comparison, we use lcmp followed by ifgt/iflt
            //

            else if (stackTop.PrimitiveType == TypeCode.Int64 ||
                     stackTop.PrimitiveType == TypeCode.UInt64)
            {
                op = 0x94; // lcmp (long)
            }

            //
            // for signed integer comparison, we have if_icmplt/if_icmpgt
            // which directly compare two integers and branch
            //

            else if (stackTop.PrimitiveType == TypeCode.Int32 ||
                     stackTop.PrimitiveType == TypeCode.UInt32 ||
                     stackTop.PrimitiveType == TypeCode.Int16 ||
                     stackTop.PrimitiveType == TypeCode.UInt16 ||
                     stackTop.PrimitiveType == TypeCode.SByte ||
                     stackTop.PrimitiveType == TypeCode.Byte ||
                     stackTop.PrimitiveType == TypeCode.Char ||
                     stackTop.PrimitiveType == TypeCode.Boolean)
            {
                return((byte)(greater ? 0xA3     // if_icmpgt
                                       : 0xA1)); // if_icmplt
            }

            else
            {
                throw new InvalidProgramException();
            }

            //
            // return the selected opcode
            //

            if (op != 0)
            {
                code.NewInstruction(op, null, null);
            }

            return((byte)(greater ? 0x9D     // ifgt
                                   : 0x9B)); // iflt
        }
예제 #8
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);
        }
예제 #9
0
        public static void Calculation(JavaCode code, Code cilOp,
                                       Mono.Cecil.Cil.Instruction cilInst)
        {
            if (cilOp == Code.And &&
                CodeBuilder.IsAndBeforeShift(cilInst.Previous, code))
            {
                // jvm shift instructions mask the shift count, so
                // eliminate AND-ing with 31 and 63 prior to a shift
                code.NewInstruction(0x00 /* nop */, null, null);
                return;
            }

            var stackTop1 = code.StackMap.PopStack(CilMain.Where);

            if (cilOp == Code.Sub && CodeSpan.SubOffset(stackTop1, code))
            {
                return;
            }
            var type1 = GetNumericTypeCode(stackTop1);

            if (cilOp == Code.Not)
            {
                BitwiseNot(code, type1);
                return;
            }

            byte op;

            if (cilOp == Code.Neg)
            {
                op = 0x74; // ineg
            }
            else
            {
                var stackTop2 = code.StackMap.PopStack(CilMain.Where);
                if ((cilOp == Code.Add || cilOp == Code.Add_Ovf_Un) &&
                    CodeSpan.AddOffset(stackTop1, stackTop2, code))
                {
                    return;
                }

                char kind;
                var  type2 = type1;
                type1 = GetNumericTypeCode(stackTop2);

                switch (cilOp)
                {
                case Code.Add:      op = 0x60; kind = 'A'; break;       // iadd

                case Code.Sub:      op = 0x64; kind = 'A'; break;       // isub

                case Code.Mul:      op = 0x68; kind = 'A'; break;       // imul

                case Code.Div:      op = 0x6C; kind = 'A'; break;       // idiv

                case Code.Rem:      op = 0x70; kind = 'A'; break;       // irem

                case Code.And:      op = 0x7E; kind = 'L'; break;       // iand

                case Code.Or:       op = 0x80; kind = 'L'; break;       // ior

                case Code.Xor:      op = 0x82; kind = 'L'; break;       // ixor

                case Code.Shl:      op = 0x78; kind = 'S'; break;       // ishl

                case Code.Shr:      op = 0x7A; kind = 'S'; break;       // ishr

                case Code.Shr_Un:   op = 0x7C; kind = 'S'; break;       // iushr

                case Code.Div_Un:
                case Code.Rem_Un:
                    op = 0x00; kind = 'U'; break;

                case Code.Add_Ovf:
                case Code.Sub_Ovf:
                case Code.Mul_Ovf:
                case Code.Add_Ovf_Un:
                case Code.Sub_Ovf_Un:
                case Code.Mul_Ovf_Un:
                    op = 0x00; kind = 'A'; break;

                default:            throw new InvalidProgramException();
                }

                bool ok = true;
                if (kind == 'S')
                {
                    // second operand must be integer shift count
                    if (type2 != TypeCode.Int32)
                    {
                        ok = false;
                    }
                }
                else
                {
                    // logical and arithmetic operands must be same type
                    if (type1 != type2)
                    {
                        if (kind == 'A' && type1 == TypeCode.Int64 && type2 == TypeCode.Int32)
                        {
                            // special case:  convert the second operand to Int64
                            code.NewInstruction(0x85 /* i2l */, null, null);
                            code.StackMap.PushStack(JavaType.LongType);
                            code.StackMap.PushStack(JavaType.LongType);
                            code.StackMap.PopStack(CilMain.Where);
                            code.StackMap.PopStack(CilMain.Where);
                        }
                        else if (kind == 'A' && type1 == TypeCode.Int32 && type2 == TypeCode.Int64)
                        {
                            // special case:  convert the second operand to Int32
                            code.NewInstruction(0x88 /* l2i */, null, null);
                        }
                        else
                        {
                            ok = false;
                        }
                    }

                    if (kind == 'L')
                    {
                        // logical operation requires integer operands
                        if (type1 != TypeCode.Int32 && type1 != TypeCode.Int64)
                        {
                            ok = false;
                        }
                    }
                }

                if (!ok)
                {
                    throw new Exception($"unexpected opcode or operands ({type1} and {type2})");
                }

                if (kind == 'A' && op == 0)
                {
                    OverflowArithmetic(code, type1, cilOp);
                    return;
                }

                if (kind == 'U')
                {
                    UnsignedDivide(code, type1, (cilOp == Code.Rem_Un));
                    return;
                }
            }

            if (type1 == TypeCode.Int64)
            {
                op++;       // ixxx -> lxxx
            }
            else if (type1 == TypeCode.Single)
            {
                op += 2;    // ixxx -> fxxx
            }
            else if (type1 == TypeCode.Double)
            {
                op += 3;    // ixxx -> dxxx
            }
            code.NewInstruction(op, null, null);
            code.StackMap.PushStack(CilType.From(new JavaType(type1, 0, null)));
        }
예제 #10
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));
            }
        }