Exemplo n.º 1
0
        void InitLocalsRefs2(CilType plainType, BoxedType boxedType, bool arg, int index)
        {
            if (arg)
            {
                code.NewInstruction(plainType.LoadOpcode, null, index);
            }
            else
            {
                code.NewInstruction(plainType.InitOpcode, null, null);
            }

            stackMap.PushStack(plainType);

            if (boxedType != null)
            {
                boxedType.BoxValue(code);
            }
            else if (plainType.IsGenericParameter)
            {
                GenericUtil.ValueClone(code);
            }
            else
            {
                CilMethod.ValueMethod(CilMethod.ValueClone, code);
                code.NewInstruction(0xC0 /* checkcast */, plainType, null);
            }

            code.NewInstruction(0x3A /* astore */, null, index);
            stackMap.PopStack(CilMain.Where);
        }
Exemplo n.º 2
0
        override public object CreateFromString(string input)
        {
            if (BoxedType != null)
            {
                return(BoxInstance(BoxedType.CreateFromString(input)));
            }

            if (CreateFromStringMethod != null)
            {
                return(this.CreateFromStringMethod(input));
            }
            else if (_enumValues != null)
            {
                int value = 0;

                string[] valueParts = input.Split(',');

                foreach (string valuePart in valueParts)
                {
                    object partValue;
                    int    enumFieldValue = 0;
                    try
                    {
                        if (_enumValues.TryGetValue(valuePart.Trim(), out partValue))
                        {
                            enumFieldValue = global::System.Convert.ToInt32(partValue);
                        }
                        else
                        {
                            try
                            {
                                enumFieldValue = global::System.Convert.ToInt32(valuePart.Trim());
                            }
                            catch (global::System.FormatException)
                            {
                                foreach (string key in _enumValues.Keys)
                                {
                                    if (string.Compare(valuePart.Trim(), key, global::System.StringComparison.OrdinalIgnoreCase) == 0)
                                    {
                                        if (_enumValues.TryGetValue(key.Trim(), out partValue))
                                        {
                                            enumFieldValue = global::System.Convert.ToInt32(partValue);
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        value |= enumFieldValue;
                    }
                    catch (global::System.FormatException)
                    {
                        throw new global::System.ArgumentException(input, FullName);
                    }
                }

                return(value);
            }
            throw new global::System.ArgumentException(input, FullName);
        }
Exemplo n.º 3
0
        public static CilType CastMaybeGeneric(CilType castType, bool valueOnly, JavaCode code)
        {
            if (!castType.IsGenericParameter)
            {
                return(castType);
            }

            if (!valueOnly)
            {
                GenericUtil.ValueLoad(code);
            }

            var genericMark = CilMain.GenericStack.Mark();

            var(resolvedType, resolvedIndex) = CilMain.GenericStack.Resolve(castType.JavaName);

            if (resolvedIndex == 0)
            {
                if (valueOnly)
                {
                    // this flag is set when called from LoadFieldAddress.  we can cast
                    // the generic field to the actual type only if it is a value type
                    if (resolvedType.IsValueClass)
                    {
                        castType = resolvedType;
                        code.NewInstruction(0xC0 /* checkcast */, castType.AsWritableClass, null);
                    }
                    else if (castType.IsByReference)
                    {
                        var boxedType = new BoxedType(resolvedType, false);
                        code.NewInstruction(0xC0 /* checkcast */, boxedType, null);
                        castType = boxedType;
                    }
                }
                else
                {
                    // this flag is clear whe called from LoadFieldValue and
                    // PushMethodReturnType.  we can cast to any known actual types.

                    var arrayRank = castType.GetMethodGenericParameter()?.ArrayRank ?? 0;
                    castType = (arrayRank == 0) ? resolvedType : resolvedType.AdjustRank(arrayRank);

                    if (!castType.IsReference)
                    {
                        var boxedType = new BoxedType(castType, false);
                        code.NewInstruction(0xC0 /* checkcast */, boxedType, null);
                        boxedType.GetValue(code);
                    }
                    else
                    {
                        code.NewInstruction(0xC0 /* checkcast */, castType.AsWritableClass, null);
                    }
                }
            }

            CilMain.GenericStack.Release(genericMark);
            return(castType);
        }
Exemplo n.º 4
0
        public void Address(CilType arrayType)
        {
            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 (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));
            }
        }
Exemplo n.º 5
0
        public static void ValueCopy(CilType valueType, JavaCode code, bool swap = false)
        {
            // if 'from' value is pushed before 'into' object, call with swap == false
            // if 'into' object is pushed before 'from' value, call with swap == true
            if (valueType.IsGenericParameter)
            {
                if (swap)
                {
                    code.NewInstruction(0x5F /* swap */, null, null);
                }
                else
                {
                    // if storing a primitive value into a generic type,
                    // and the generic type can be resolved to a primitive type,
                    // then use a boxed-set method call

                    var stackArray    = code.StackMap.StackArray();
                    int stackArrayLen = stackArray.Length;
                    if (stackArrayLen > 0 && (!stackArray[stackArrayLen - 1].IsReference))
                    {
                        var genericMark = CilMain.GenericStack.Mark();
                        var(primitiveType, _) = CilMain.GenericStack.Resolve(valueType.JavaName);
                        CilMain.GenericStack.Release(genericMark);

                        if (!primitiveType.IsReference)
                        {
                            var boxedType = new BoxedType(primitiveType, false);
                            code.NewInstruction(0xC0 /* checkcast */, boxedType, null);
                            boxedType.SetValueVO(code);
                            return;
                        }
                    }
                }

                code.NewInstruction(0xB8 /* invokestatic */, SystemGenericType,
                                    new JavaMethod("Copy", JavaType.VoidType,
                                                   JavaType.ObjectType, JavaType.ObjectType));
            }
            else
            {
                if (swap)
                {
                    code.NewInstruction(0x5F /* swap */, null, null);
                }
                CilMethod.ValueMethod(CilMethod.ValueCopyTo, code);
            }
        }
Exemplo n.º 6
0
        void UnboxObject(Code cilOp, object data)
        {
            if (data is TypeReference typeRef)
            {
                var dataType = CilType.From(typeRef);

                if (dataType.IsValueClass)
                {
                    if (dataType.IsGenericParameter)
                    {
                        if (cilOp == Code.Unbox_Any)
                        {
                            // unboxing (casting) a concrete type as a generic type
                            var stackTop = (CilType)code.StackMap.PopStack(CilMain.Where);
                            if (stackTop.Equals(JavaType.ObjectType) || dataType.Equals(stackTop))
                            {
                                code.NewInstruction(0x00 /* nop */, null, null);
                            }
                            else
                            {
                                code.NewInstruction(0xC0 /* checkcast */, dataType, null);
                            }
                            code.StackMap.PushStack(dataType);
                        }
                        else // plain Unbox
                        {
                            throw new InvalidProgramException();
                        }
                    }
                    else
                    {
                        code.StackMap.PopStack(CilMain.Where);
                        code.NewInstruction(0xC0 /* checkcast */, dataType, null);
                        code.StackMap.PushStack(dataType);
                    }
                }

                else if (!dataType.IsReference)
                {
                    var boxedType = new BoxedType(dataType, false);

                    var fromType = code.StackMap.PopStack(CilMain.Where);
                    if (!fromType.Equals(boxedType))
                    {
                        code.NewInstruction(0xC0 /* checkcast */, boxedType, null);
                    }

                    boxedType.GetValue(code);
                    code.StackMap.PushStack(dataType);
                }

                else
                {
                    if (cilOp == Code.Unbox_Any)
                    {
                        NullCheck();
                        CastToClass(data);
                    }
                    else // plain Unbox
                    {
                        throw new InvalidProgramException();
                    }
                }
            }
        }
Exemplo n.º 7
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);
            }
        }
Exemplo n.º 8
0
        bool ImportParameters(MethodReference fromMethod)
        {
            bool appendSuffix = false;

            int n = fromMethod.HasParameters ? fromMethod.Parameters.Count : 0;

            Parameters = new List <JavaFieldRef>(n);

            for (int i = 0; i < n; i++)
            {
                var fromParameterType = fromMethod.Parameters[i].ParameterType;
                var paramType         = CilType.From(fromParameterType);

                if (paramType.IsPointer)
                {
                    if (paramType.IsValueClass || (!paramType.IsReference))
                    {
                        paramType = CilType.MakeSpanOf(paramType);
                    }
                    else
                    {
                        throw CilMain.Where.Exception("invalid pointer type in parameter");
                    }
                }

                if (paramType.IsGenericParameter)
                {
                    appendSuffix = true;
                    var nm = "-generic-";
                    if (paramType.IsArray)
                    {
                        nm += "array-" + paramType.ArrayRank + "-";
                    }
                    if (paramType.IsByReference)
                    {
                        nm = "-ref" + nm.Replace("&", "");
                    }
                    nm       += "$" + ((GenericParameter)fromParameterType.GetElementType()).Position;
                    paramType = CilType.WrapMethodGenericParameter(paramType, nm);
                    Flags    |= GEN_ARGS;
                }

                if (paramType.IsByReference)
                {
                    if (paramType.IsValueClass)
                    {
                        paramType    = paramType.MakeByRef();
                        appendSuffix = true;
                    }
                    else
                    {
                        // byref of any reference type parameter becomes system.Reference,
                        // so add a unique method name suffix
                        var paramBoxedType = new BoxedType(paramType, false);
                        paramType     = paramBoxedType;
                        appendSuffix |= paramBoxedType.IsBoxedReference;
                    }
                }

                if (!appendSuffix)
                {
                    appendSuffix |= fromParameterType.IsGenericInstance;

                    if (!paramType.IsReference)
                    {
                        appendSuffix |= ShouldRenamePrimitive(paramType);
                    }
                }

                Parameters.Add(new JavaFieldRef("", paramType));
            }

            var returnType = CilType.From(fromMethod.ReturnType);

            if (returnType.IsGenericParameter)
            {
                returnType = CilType.WrapMethodGenericParameter(returnType);
            }
            else if (returnType.IsByReference)
            {
                returnType = new BoxedType(returnType, false);
            }
            ReturnType = returnType;

            appendSuffix |= fromMethod.ReturnType.IsGenericInstance;

            return(appendSuffix);
Exemplo n.º 9
0
        int InitLocalsVars(MethodBody cilBody, List <CilType> localTypes, int nextIndex)
        {
            int highestIndex = -1;

            if (cilBody.HasVariables)
            {
                foreach (var cilVar in cilBody.Variables)
                {
                    if (cilVar.Index > highestIndex)
                    {
                        highestIndex = cilVar.Index;
                    }
                }
            }

            varToLocalMap = new int[highestIndex + 1];

            if (cilBody.HasVariables)
            {
                foreach (var cilVar in cilBody.Variables)
                {
                    CilMain.Where.Push("local #" + cilVar.Index);

                    var genericMark = CilMain.GenericStack.Mark();
                    var varType     = CilMain.GenericStack.EnterType(cilVar.VariableType);

                    if (varType.IsValueClass || varType.IsPointer)
                    {
                        bool isByReference = varType.IsByReference;

                        if (varType.IsPointer)
                        {
                            varType = CilType.MakeSpanOf(varType);
                        }

                        // value classes are allocated at the top of the method
                        if (!isByReference)
                        {
                            ValueUtil.InitLocal(varType, nextIndex, code);
                            varType = varType.MakeClonedAtTop();
                        }
                    }
                    else if (varType.IsByReference)
                    {
                        varType = new BoxedType(varType, false);
                    }
                    else if (varType.IsArray && varType.IsGenericParameter)
                    {
                        // note that GenericArrayType is compared by reference
                        // in CodeArrays, to detect an array of a generic type T[]
                        varType = CodeArrays.GenericArrayType;
                    }

                    varToLocalMap[cilVar.Index] = nextIndex;
                    nextIndex += varType.Category;

                    localTypes.Add(varType);
                    while (nextIndex > localTypes.Count)
                    {
                        localTypes.Add(null);
                    }

                    CilMain.GenericStack.Release(genericMark);
                    CilMain.Where.Pop();
                }
            }

            return(nextIndex);
        }
Exemplo n.º 10
0
        public static void BuildGenericProxy2(CilInterfaceMethod ifcMethod, CilMethod targetMethod,
                                              bool parentField, CilType intoType, JavaClass ifcClass)
        {
            //
            // create proxy method
            //

            var targetMethod2 = targetMethod.WithGenericParameters;
            var ifcMethod2    = ifcMethod.Method.WithGenericParameters;

            var newMethod = new JavaMethod(ifcClass, targetMethod2);

            newMethod.Name  = ifcMethod2.Name;
            newMethod.Flags = JavaAccessFlags.ACC_PUBLIC | JavaAccessFlags.ACC_BRIDGE;

            var code = newMethod.Code = new JavaCode();

            code.Method       = newMethod;
            code.Instructions = new List <JavaCode.Instruction>();

            //
            // push a reference to the parent object
            //

            code.NewInstruction(0x19 /* aload */, null, (int)0);
            if (parentField)
            {
                code.NewInstruction(0xB4 /* getfield */, new JavaType(0, 0, ifcClass.Name),
                                    new JavaFieldRef(ParentFieldName, intoType));
            }

            //
            // push all other parameters
            //

            int numArgs  = newMethod.Parameters.Count;
            int index    = 1;
            int maxStack = 1;

            for (int i = 0; i < numArgs; i++)
            {
                var ifcArg = ifcMethod2.Parameters[i].Type;
                code.NewInstruction(ifcArg.LoadOpcode, null, (int)index);
                index += ifcArg.Category;

                var clsArg = (CilType)targetMethod2.Parameters[i].Type;
                if (JavaType.ObjectType.Equals(ifcArg))
                {
                    if (!clsArg.IsReference)
                    {
                        var boxedArg = new BoxedType(clsArg, false);
                        code.NewInstruction(0xC0 /* checkcast */, boxedArg, null);
                        boxedArg.GetValue(code);
                    }
                    else if (!JavaType.ObjectType.Equals(clsArg))
                    {
                        code.NewInstruction(0xC0 /* checkcast */, clsArg, null);
                    }
                    // a parameter in the target method may be a concrete type,
                    // but if it is a generic java.lang.Object in the interface,
                    // then it must be a generic java.lang.Object in the proxy
                    newMethod.Parameters[i] = new JavaFieldRef("", ifcArg);
                }
                maxStack += clsArg.Category;
            }

            //
            // invoke proxy target method
            //

            code.NewInstruction(0xB6 /* invokevirtual */, intoType, targetMethod2);

            //
            // return value from method
            //

            var clsRet = (CilType)targetMethod2.ReturnType;
            var ifcRet = ifcMethod2.ReturnType;

            if (JavaType.ObjectType.Equals(ifcRet))
            {
                if (!clsRet.IsReference)
                {
                    var boxedArg = new BoxedType(clsRet, false);
                    boxedArg.BoxValue(code);
                }
                // the return value in the target method may be a concrete type,
                // but if it is a generic java.lang.Object in the interface,
                // then it must also be a generic java.lang.Object in the proxy
                newMethod.ReturnType = ifcRet;
                code.NewInstruction(ifcRet.ReturnOpcode, null, null);
            }
            else
            {
                code.NewInstruction(clsRet.ReturnOpcode, null, null);
            }

            code.MaxLocals = index;
            code.MaxStack  = maxStack;

            ifcClass.Methods.Add(newMethod);
        }
Exemplo n.º 11
0
        void InitLocalsRefs(MethodDefinition cilMethod, List <CilType> localTypes)
        {
            // if the method includes instructions that take the address of
            // a local (argument/variable), then:
            //
            // if it is a primitive value type, or a reference, then we have
            // to box that into a system.<primitive> or system.Reference.
            //
            // if it is a class value type, or a generic parameter, and if
            // it was not passed by reference, then we have to make a copy
            // of the incoming value.
            //
            // a pointer argument is actually passed as a span (value type)
            // so if it is modified, we have to make a copy, as above.
            //
            // (if it was a generic parameter which represents a value type,
            // then a copy was already made when the value was loaded.)

            var processed = new bool[localTypes.Count];

            foreach (var inst in cilMethod.Body.Instructions)
            {
                int  index         = -1;
                bool arg           = false;
                bool isPointerSpan = false;

                var instOpc = inst.OpCode.Code;
                if (instOpc == Code.Ldarga || instOpc == Code.Ldarga_S)
                {
                    if (inst.Operand is ParameterDefinition param)
                    {
                        index = ArgumentIndex(param.Sequence);
                        arg   = true;
                    }
                }
                else if (instOpc == Code.Starg || instOpc == Code.Starg_S)
                {
                    if (inst.Operand is ParameterDefinition param)
                    {
                        var paramType = param.ParameterType;
                        if ((paramType.IsValueType && (!paramType.IsPrimitive)) ||
                            (isPointerSpan = paramType.IsPointer))
                        {
                            index = ArgumentIndex(param.Sequence);
                            arg   = true;
                        }
                    }
                }
                else if (instOpc == Code.Ldloca || instOpc == Code.Ldloca_S)
                {
                    if (inst.Operand is VariableDefinition var)
                    {
                        index = VariableIndex(var.Index);
                        arg   = false;
                    }
                }

                //
                // check if already processed, or does not require processing
                //

                if (index == -1 || processed[index])
                {
                    continue;
                }
                processed[index] = true;

                var plainType = localTypes[index];
                if (plainType.IsByReference)
                {
                    continue;
                }

                //
                // copy class value type argument, or generic parameter, if
                // it was indeed passed by value, because we know the method
                // is going to modify the value.  (this also applies to a
                // pointer, which is passed as a span, a value type object.)
                //

                if (plainType.IsValueClass ||
                    plainType.IsGenericParameter ||
                    isPointerSpan)
                {
                    if (arg)
                    {
                        InitLocalsRefs2(plainType, null, true, index);

                        if (plainType.IsGenericParameter || isPointerSpan)
                        {
                            // must not set the stackmap for a generic parameter,
                            // see InitLocalsArgs for the difference between the
                            // stackmap and the localTypes array
                            localTypes[index] = plainType.MakeClonedAtTop();
                        }
                        else
                        {
                            var byrefType = plainType.MakeClonedAtTop().MakeByRef();
                            localTypes[index] = byrefType;
                            stackMap.SetLocal(index, byrefType);
                        }
                    }
                }
                else
                {
                    //
                    // otherwise the method is going to load the address of a local
                    // (either argument or variable) which is a primitive value, or
                    // a reference, so we have to box that local
                    //

                    // note that boxedType will be marked as if MakeClonedAtTop()
                    var boxedType = new BoxedType(plainType, true);
                    localTypes[index] = boxedType;
                    stackMap.SetLocal(index, boxedType);

                    InitLocalsRefs2(plainType, boxedType, arg, index);
                }
            }
        }
Exemplo n.º 12
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);
        }
Exemplo n.º 13
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));
            }
        }