diff --git a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs index 88faf7d411d..9f9d90a667a 100644 --- a/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs +++ b/src/ILCompiler.CppCodeGen/src/CppCodeGen/ILToCppImporter.cs @@ -1046,44 +1046,15 @@ private void ImportCall(ILOpcode opcode, int token) ExpressionEntry v = (ExpressionEntry)_stack[_stack.Top - (methodSignature.Length + 1)]; string typeDefName = _writer.GetCppMethodName(method); - _writer.AppendSignatureTypeDef(_builder, typeDefName, method.Signature, method.OwningType); + _writer.AppendSignatureTypeDef(_builder, typeDefName, method.Signature, method.OwningType); string functionPtr = NewTempName(); AppendEmptyLine(); Append("void*"); Append(functionPtr); - Append(" = (void*) (("); - Append(typeDefName); - // Call method to find implementation address - Append(") System_Private_CoreLib::System::Runtime::DispatchResolve::FindInterfaceMethodImplementationTarget("); - - // Get EEType of current object (interface implementation) - Append("::System_Private_CoreLib::System::Object::get_EEType((::System_Private_CoreLib::System::Object*)"); - Append(v.Name); - Append(")"); - - Append(", "); - - // Get EEType of interface - Append("((::System_Private_CoreLib::Internal::Runtime::EEType *)("); - Append(_writer.GetCppTypeName(method.OwningType)); - Append("::__getMethodTable()))"); - - Append(", "); - - // Get slot of implementation - Append("(uint16_t)"); - Append("("); - Append(_writer.GetCppTypeName(method.OwningType)); - Append("::"); - Append("__getslot__"); - Append(_writer.GetCppMethodName(method)); - Append("("); - Append(v.Name); - Append("))"); - - Append("));"); + Append(" = (void*) "); + GetFunctionPointerForInterfaceMethod(method, v, typeDefName); PushExpression(StackValueKind.ByRef, functionPtr); } @@ -1236,6 +1207,41 @@ private void ImportCall(ILOpcode opcode, int token) } } + private void GetFunctionPointerForInterfaceMethod(MethodDesc method, ExpressionEntry v, string typeDefName) + { + Append("(("); + Append(typeDefName); + // Call method to find implementation address + Append(") System_Private_CoreLib::System::Runtime::DispatchResolve::FindInterfaceMethodImplementationTarget("); + + // Get EEType of current object (interface implementation) + Append("::System_Private_CoreLib::System::Object::get_EEType((::System_Private_CoreLib::System::Object*)"); + Append(v.Name); + Append(")"); + + Append(", "); + + // Get EEType of interface + Append("((::System_Private_CoreLib::Internal::Runtime::EEType *)("); + Append(_writer.GetCppTypeName(method.OwningType)); + Append("::__getMethodTable()))"); + + Append(", "); + + // Get slot of implementation + Append("(uint16_t)"); + Append("("); + Append(_writer.GetCppTypeName(method.OwningType)); + Append("::"); + Append("__getslot__"); + Append(_writer.GetCppMethodName(method)); + Append("("); + Append(v.Name); + Append("))"); + + Append("));"); + } + private void PassCallArguments(MethodSignature methodSignature, TypeDesc thisArgument) { int signatureLength = methodSignature.Length; @@ -1325,22 +1331,51 @@ private void ImportLdFtn(int token, ILOpcode opCode) { MethodDesc method = (MethodDesc)_methodIL.GetObject(token); - if (opCode == ILOpcode.ldvirtftn) + if (opCode == ILOpcode.ldvirtftn && method.IsVirtual && method.OwningType.IsInterface) { - if (method.IsVirtual) - throw new NotImplementedException(); - } + AddVirtualMethodReference(method); + var entry = new LdTokenEntry(StackValueKind.NativeInt, NewTempName(), method); + ExpressionEntry v = (ExpressionEntry)_stack.Pop(); + string typeDefName = _writer.GetCppMethodName(method); + _writer.AppendSignatureTypeDef(_builder, typeDefName, method.Signature, method.OwningType); - AddMethodReference(method); + AppendEmptyLine(); - var entry = new LdTokenEntry(StackValueKind.NativeInt, NewTempName(), method); - PushTemp(entry); - Append("(intptr_t)&"); - Append(_writer.GetCppTypeName(method.OwningType)); - Append("::"); - Append(_writer.GetCppMethodName(method)); + PushTemp(entry); + Append("(intptr_t) "); + GetFunctionPointerForInterfaceMethod(method, v, typeDefName); + } + else + { + AddMethodReference(method); + var entry = new LdTokenEntry(StackValueKind.NativeInt, NewTempName(), method); + + if (opCode == ILOpcode.ldvirtftn && method.IsVirtual) + { + //ldvirtftn requires an object instance, we have to pop one off the stack + //then call the associated getslot method passing in the object instance to get the real function pointer + ExpressionEntry v = (ExpressionEntry)_stack.Pop(); + PushTemp(entry); + Append("(intptr_t)"); + Append(_writer.GetCppTypeName(method.OwningType)); + Append("::__getslot__"); + Append(_writer.GetCppMethodName(method)); + Append("("); + Append(v.Name); + Append(")"); + AppendSemicolon(); + } + else + { + PushTemp(entry); + Append("(intptr_t)&"); + Append(_writer.GetCppTypeName(method.OwningType)); + Append("::"); + Append(_writer.GetCppMethodName(method)); - AppendSemicolon(); + AppendSemicolon(); + } + } } private void ImportLoadInt(long value, StackValueKind kind) @@ -2675,6 +2710,11 @@ private void AddMethodReference(MethodDesc method) _dependencies.Add(_nodeFactory.MethodEntrypoint(method)); } + private void AddVirtualMethodReference(MethodDesc method) + { + _dependencies.Add(_nodeFactory.VirtualMethodUse(method)); + } + private void AddFieldReference(FieldDesc field) { if (field.IsStatic)