public int CalculateInterfaceIndex(ITypeInformation interfaceType) => boxedType.CalculateInterfaceIndex(interfaceType);
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 }; } }); }