Esempio n. 1
0
 public int CalculateInterfaceIndex(ITypeInformation interfaceType) =>
 boxedType.CalculateInterfaceIndex(interfaceType);
Esempio n. 2
0
        public static Func <IExtractContext, string[]> Apply(
            IMethodInformation method,
            DecodeContext decodeContext,
            bool isVirtualCall)
        {
            // ECMA-335 I.12.4.1.4: Virtual calling convention

            // This method is too complex because it will try devirtualizing.

            //////////////////////////////////////////////////////////
            // Step 1:

            // Constrained prefix applied, drop virtual call and hack the boxing for arg0 if required.
            //   (See ConstrainedConverter.)
            ITypeInformation arg0ValueType = null;
            var prefixCode = decodeContext.PrefixCode;

            if (prefixCode?.OpCode == OpCodes.Constrained)
            {
                // 'The constrained. prefix is permitted only on a callvirt instruction.'
                if (!isVirtualCall)
                {
                    throw new InvalidProgramSequenceException(
                              "Cannot apply constrained prefix: Location={0}",
                              decodeContext.CurrentCode.RawLocation);
                }

                // ECMA-335 III.2.1 constrained. - (prefix) invoke a member on a value of a variable type
                var constrainedType = (ITypeInformation)(prefixCode.Operand);

                // 'If thisType is a value type...'
                if (constrainedType.IsValueType)
                {
                    // All declared methods from derived to base types.
                    var allDeclaredMethods = constrainedType.AllInheritedDeclaredMethods;

                    // '...and thisType implements method then'
                    var implementationMethod = allDeclaredMethods.First(
                        dm => MetadataUtilities.VirtualMethodSignatureComparer.Equals(dm, method));

                    // Drop virtual call and turn to the direct call (devirtualize)
                    isVirtualCall = false;
                    method        = implementationMethod;

                    // '...and thisType does not implement method then'
                    if (!implementationMethod.DeclaringType.Equals(constrainedType))
                    {
                        // 'ptr is dereferenced, boxed, and passed as the ‘this’ pointer to the callvirt of method'

                        // VERY DIRTY: The constrained type uses below.
                        arg0ValueType = constrainedType;
                    }
                }
            }

            //////////////////////////////////////////////////////////
            // Step 2:

            ILocalVariableInformation requiredBoxingAtArg0PointerVariable  = null;
            ILocalVariableInformation requiredCastingAtArg0PointerVariable = null;

            // Construct parameters with expressions.
            var pairParameters = method.Parameters.
                                 Reverse(). // arg(n - 1) ... arg0
                                 Select(parameter =>
            {
                var arg = decodeContext.PopStack();
                return((parameter.Index == 0) ?
                       GetArg0ParameterInformation(
                           decodeContext, ref method, parameter, arg,
                           ref arg0ValueType,
                           ref requiredBoxingAtArg0PointerVariable,
                           ref requiredCastingAtArg0PointerVariable,
                           ref isVirtualCall) :
                       (type: parameter.TargetType, variable: arg, format: "{0}"));
            }).
                                 Reverse().
                                 ToArray();

            //////////////////////////////////////////////////////////
            // Step 3: Fixing special cases

            var codeInformation = decodeContext.CurrentCode;
            ILocalVariableInformation result;

            // TODO: HACK: IL2C can't handle the generic types/methods in this version.
            //   Roslyn will generate implementation for the event member with using for
            //   "System.Threading.Interlocked.CompareExchange<T>(...)" method.
            //   It's special resolver for event member.
            if ((method.UniqueName == "T System.Threading.Interlocked::CompareExchange(T&,T,T)") &&
                pairParameters[1].variable.TargetType.IsReferenceType)
            {
                result = decodeContext.PushStack(pairParameters[1].variable.TargetType);

                return(extractContext =>
                {
                    var parameters = pairParameters.Select(parameter =>
                                                           new Utilities.RightExpressionGivenParameter(
                                                               parameter.variable.TargetType,
                                                               parameter.variable,
                                                               string.Format(parameter.format, extractContext.GetSymbolName(parameter.variable)))).
                                     ToArray();

                    var parameterString = Utilities.GetGivenParameterDeclaration(
                        parameters,
                        extractContext,
                        codeInformation);

                    return new[]
                    {
                        string.Format(
                            "{0} = ({1})System_Threading_Interlocked_CompareExchange_6({2})",
                            extractContext.GetSymbolName(result),
                            pairParameters[1].variable.TargetType.CLanguageTypeName,
                            parameterString)
                    };
                });
            }

            if (method.ReturnType.IsVoidType)
            {
                // HACK: If we will call the RuntimeHelpers.InitializeArray, we can memoize array type hint.
                //   (See LdtokenConverter.)
                if (method.FriendlyName.StartsWith(
                        "System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray"))
                {
                    Debug.Assert(pairParameters.Length == 2);
                    Debug.Assert(pairParameters[1].variable.HintInformation is string);

                    decodeContext.PrepareContext.RegisterDeclaredValuesHintType(
                        (string)pairParameters[1].variable.HintInformation,
                        pairParameters[0].variable.TargetType);
                }

                result = null;
            }
            else
            {
                result = decodeContext.PushStack(method.ReturnType);
            }

            // Register callee method declaring type (at the file scope).
            decodeContext.PrepareContext.RegisterType(method.DeclaringType, decodeContext.Method);

            return(extractContext =>
            {
                var receiveResultExpression = (result != null) ?
                                              string.Format("{0} = ", extractContext.GetSymbolName(result)) :
                                              string.Empty;

                var parameters = pairParameters.Select(parameter =>
                                                       new Utilities.RightExpressionGivenParameter(
                                                           parameter.type,
                                                           parameter.variable,
                                                           string.Format(parameter.format, extractContext.GetSymbolName(parameter.variable)))).
                                 ToArray();

                var parameterString = Utilities.GetGivenParameterDeclaration(
                    parameters,
                    extractContext,
                    codeInformation);

                // Construct call expression between virtual and non-virtual.
                string callExpression;
                if (isVirtualCall && method.IsVirtual && !method.IsSealed)
                {
                    var overloadIndex = method.DeclaringType.CalculatedVirtualMethods.
                                        First(entry => entry.method.Equals(method)).
                                        overloadIndex;

                    callExpression = string.Format(
                        "{0}{1}->vptr0__->{2}({3})",
                        receiveResultExpression,
                        extractContext.GetSymbolName(pairParameters[0].variable),
                        method.GetCLanguageDeclarationName(overloadIndex),
                        parameterString);
                }
                else
                {
                    callExpression = string.Format(
                        "{0}{1}({2})",
                        receiveResultExpression,
                        method.CLanguageFunctionName,
                        parameterString);
                }

                // If requires boxing expression
                if (requiredBoxingAtArg0PointerVariable != null)
                {
                    Debug.Assert(arg0ValueType != null);

                    // Emit call expression with boxing expression.
                    return new[] {
                        string.Format(
                            "{0} = il2c_box({1}, {2})",
                            extractContext.GetSymbolName(pairParameters[0].variable),
                            extractContext.GetSymbolName(requiredBoxingAtArg0PointerVariable),
                            arg0ValueType.MangledUniqueName),
                        callExpression
                    };
                }
                // If requires casting expression
                else if (requiredCastingAtArg0PointerVariable != null)
                {
                    // Emit call expression with casting expression.
                    return new[] {
                        string.Format(
                            "{0} = il2c_cast_from_boxed_to_interface({1}, {2}, {3}, {4})",
                            extractContext.GetSymbolName(pairParameters[0].variable),
                            method.DeclaringType.MangledUniqueName,
                            arg0ValueType.ElementType.CLanguageStaticSizeOfExpression,
                            arg0ValueType.CalculateInterfaceIndex(method.DeclaringType),
                            extractContext.GetSymbolName(requiredCastingAtArg0PointerVariable)),
                        callExpression
                    };
                }
                else
                {
                    // Emit only call expression
                    return new[] { callExpression };
                }
            });
        }