diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs index fd76cf46c..618aa3711 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.Delegate.cs @@ -603,7 +603,7 @@ public static void NativeDelegateType( { Stloc_0 }, { nop_try_this }, - // Arguments loading inside outer 'try/catch' block + // Arguments loading inside outer 'try/finally' block { nop_try_sender }, { nop_try_args }, diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs index b62708d51..0ba64c060 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IDictionary2.cs @@ -95,7 +95,7 @@ public static void Vftbl( // We can share the vtable type for 'void*' when both key and value types are reference types if (isKeyReferenceType && isValueReferenceType) { - vftblType = interopDefinitions.IReadOnlyDictionary2Vftbl; + vftblType = interopDefinitions.IDictionary2Vftbl; return; } @@ -104,7 +104,7 @@ public static void Vftbl( // the vtable type. So in this case, we just always construct a specialized new type. if (!isKeyReferenceType && !isValueReferenceType) { - vftblType = WellKnownTypeDefinitionFactory.IReadOnlyDictionary2Vftbl( + vftblType = WellKnownTypeDefinitionFactory.IDictionary2Vftbl( ns: InteropUtf8NameFactory.TypeNamespace(dictionaryType), name: InteropUtf8NameFactory.TypeName(dictionaryType, "Vftbl"), keyType: keyType, @@ -220,102 +220,57 @@ public static void IMapMethods( // Track the type (it's needed by 'IObservableMap') emitState.TrackTypeDefinition(mapMethodsType, dictionaryType, "IMapMethods"); - // Define the 'HasKey' method as follows: - // - // public static bool HasKey(WindowsRuntimeObjectReference thisReference, key) - MethodDefinition hasKeyMethod = new( - name: "HasKey"u8, - attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, - signature: MethodSignature.CreateStatic( - returnType: module.CorLibTypeFactory.Boolean, - parameterTypes: [ - interopReferences.WindowsRuntimeObjectReference.Import(module).ToReferenceTypeSignature(), - keyType.Import(module)])) - { NoInlining = true }; + // Define the 'HasKey' method + MethodDefinition hasKeyMethod = InteropMethodDefinitionFactory.IMapViewMethods.HasKey( + readOnlyDictionaryType: dictionaryType, + vftblType: vftblType, + interopReferences: interopReferences, + emitState: emitState, + module: module); // Add and implement the 'HasKey' method mapMethodsType.AddMethodImplementation( declaration: interopReferences.IMapMethodsImpl2HasKey(keyType, valueType).Import(module), method: hasKeyMethod); - // Create a method body for the 'HasKey' method - hasKeyMethod.CilMethodBody = new CilMethodBody() - { - Instructions = { { Ldnull }, { Throw } } // TODO - }; - - // Define the 'Lookup' method as follows: - // - // public static Lookup(WindowsRuntimeObjectReference thisReference, key) - MethodDefinition lookupMethod = new( - name: "Lookup"u8, - attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, - signature: MethodSignature.CreateStatic( - returnType: valueType.Import(module), - parameterTypes: [ - interopReferences.WindowsRuntimeObjectReference.Import(module).ToReferenceTypeSignature(), - keyType.Import(module)])) - { NoInlining = true }; + // Define the 'Lookup' method + MethodDefinition lookupMethod = InteropMethodDefinitionFactory.IMapViewMethods.Lookup( + readOnlyDictionaryType: dictionaryType, + vftblType: vftblType, + interopReferences: interopReferences, + emitState: emitState, + module: module); // Add and implement the 'Lookup' method mapMethodsType.AddMethodImplementation( declaration: interopReferences.IMapMethodsImpl2Lookup(keyType, valueType).Import(module), method: lookupMethod); - // Create a method body for the 'Lookup' method - lookupMethod.CilMethodBody = new CilMethodBody() - { - Instructions = { { Ldnull }, { Throw } } // TODO - }; - - // Define the 'Insert' method as follows: - // - // public static bool Insert(WindowsRuntimeObjectReference thisReference, key, value) - MethodDefinition insertMethod = new( - name: "Insert"u8, - attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, - signature: MethodSignature.CreateStatic( - returnType: module.CorLibTypeFactory.Boolean, - parameterTypes: [ - interopReferences.WindowsRuntimeObjectReference.Import(module).ToReferenceTypeSignature(), - keyType.Import(module), - valueType.Import(module)])) - { NoInlining = true }; + // Define the 'Insert' method + MethodDefinition insertMethod = InteropMethodDefinitionFactory.IMapMethods.Insert( + dictionaryType: dictionaryType, + vftblType: vftblType, + interopReferences: interopReferences, + emitState: emitState, + module: module); // Add and implement the 'Insert' method mapMethodsType.AddMethodImplementation( declaration: interopReferences.IMapMethodsImpl2Insert(keyType, valueType).Import(module), method: insertMethod); - // Create a method body for the 'Insert' method - insertMethod.CilMethodBody = new CilMethodBody() - { - Instructions = { { Ldnull }, { Throw } } // TODO - }; - - // Define the 'Remove' method as follows: - // - // public static void Remove(WindowsRuntimeObjectReference thisReference, key) - MethodDefinition removeMethod = new( - name: "Remove"u8, - attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, - signature: MethodSignature.CreateStatic( - returnType: module.CorLibTypeFactory.Boolean, - parameterTypes: [ - interopReferences.WindowsRuntimeObjectReference.Import(module).ToReferenceTypeSignature(), - keyType.Import(module)])) - { NoInlining = true }; + // Define the 'Remove' method + MethodDefinition removeMethod = InteropMethodDefinitionFactory.IMapMethods.Remove( + dictionaryType: dictionaryType, + vftblType: vftblType, + interopReferences: interopReferences, + emitState: emitState, + module: module); // Add and implement the 'Remove' method mapMethodsType.AddMethodImplementation( declaration: interopReferences.IMapMethodsImpl2Remove(keyType, valueType).Import(module), method: removeMethod); - - // Create a method body for the 'Remove' method - removeMethod.CilMethodBody = new CilMethodBody() - { - Instructions = { { Ldnull }, { Throw } } // TODO - }; } /// diff --git a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs index 5a212b348..f820a6c93 100644 --- a/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs +++ b/src/WinRT.Interop.Generator/Builders/InteropTypeDefinitionBuilder.IReadOnlyDictionary2.cs @@ -88,12 +88,14 @@ public static void Vftbl( /// The for the type. /// The type returned by . /// The instance to use. + /// The emit state for this invocation. /// The interop module being built. /// The resulting methods type. public static void IMapViewMethods( GenericInstanceTypeSignature readOnlyDictionaryType, TypeDefinition vftblType, InteropReferences interopReferences, + InteropGeneratorEmitState emitState, ModuleDefinition module, out TypeDefinition mapViewMethodsType) { @@ -112,53 +114,31 @@ public static void IMapViewMethods( module.TopLevelTypes.Add(mapViewMethodsType); - // Define the 'HasKey' method as follows: - // - // public static bool HasKey(WindowsRuntimeObjectReference thisReference, key) - MethodDefinition hasKeyMethod = new( - name: "HasKey"u8, - attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, - signature: MethodSignature.CreateStatic( - returnType: module.CorLibTypeFactory.Boolean, - parameterTypes: [ - interopReferences.WindowsRuntimeObjectReference.Import(module).ToReferenceTypeSignature(), - keyType.Import(module)])) - { NoInlining = true }; + // Define the 'HasKey' method + MethodDefinition hasKeyMethod = InteropMethodDefinitionFactory.IMapViewMethods.HasKey( + readOnlyDictionaryType: readOnlyDictionaryType, + vftblType: vftblType, + interopReferences: interopReferences, + emitState: emitState, + module: module); // Add and implement the 'HasKey' method mapViewMethodsType.AddMethodImplementation( declaration: interopReferences.IMapViewMethodsImpl2HasKey(keyType, valueType).Import(module), method: hasKeyMethod); - // Create a method body for the 'HasKey' method - hasKeyMethod.CilMethodBody = new CilMethodBody() - { - Instructions = { { Ldnull }, { Throw } } // TODO - }; - - // Define the 'Lookup' method as follows: - // - // public static Lookup(WindowsRuntimeObjectReference thisReference, key) - MethodDefinition lookupMethod = new( - name: "Lookup"u8, - attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, - signature: MethodSignature.CreateStatic( - returnType: valueType.Import(module), - parameterTypes: [ - interopReferences.WindowsRuntimeObjectReference.Import(module).ToReferenceTypeSignature(), - keyType.Import(module)])) - { NoInlining = true }; + // Define the 'Lookup' method + MethodDefinition lookupMethod = InteropMethodDefinitionFactory.IMapViewMethods.Lookup( + readOnlyDictionaryType: readOnlyDictionaryType, + vftblType: vftblType, + interopReferences: interopReferences, + emitState: emitState, + module: module); // Add and implement the 'Lookup' method mapViewMethodsType.AddMethodImplementation( declaration: interopReferences.IMapViewMethodsImpl2HasKey(keyType, valueType).Import(module), method: lookupMethod); - - // Create a method body for the 'Lookup' method - lookupMethod.CilMethodBody = new CilMethodBody() - { - Instructions = { { Ldnull }, { Throw } } // TODO - }; } /// diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IAsyncInfoMethods.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IAsyncInfoMethods.cs index fd06e8ddd..d48778629 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IAsyncInfoMethods.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IAsyncInfoMethods.cs @@ -304,6 +304,7 @@ public static MethodDefinition GetResults( { Ldloc_1 }, { Ldarg_1 }, { Ldloca_S, loc_2_resultNative }, + { Conv_U }, { Ldloc_1 }, { Ldind_I }, { Ldfld, vftblField }, diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IMapMethods.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IMapMethods.cs new file mode 100644 index 000000000..7e5baa419 --- /dev/null +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IMapMethods.cs @@ -0,0 +1,272 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using AsmResolver.DotNet; +using AsmResolver.DotNet.Code.Cil; +using AsmResolver.DotNet.Signatures; +using AsmResolver.PE.DotNet.Cil; +using AsmResolver.PE.DotNet.Metadata.Tables; +using WindowsRuntime.InteropGenerator.Generation; +using WindowsRuntime.InteropGenerator.References; +using static AsmResolver.PE.DotNet.Cil.CilOpCodes; + +namespace WindowsRuntime.InteropGenerator.Factories; + +/// +internal partial class InteropMethodDefinitionFactory +{ + /// + /// Helpers for method types for constructed IMap<K, V> interfaces. + /// + public static class IMapMethods + { + /// + /// Creates a for the Insert method for some IMap<K, V> interface. + /// + /// The for the type. + /// The vtable type for . + /// The instance to use. + /// The emit state for this invocation. + /// The interop module being built. + public static MethodDefinition Insert( + GenericInstanceTypeSignature dictionaryType, + TypeDefinition vftblType, + InteropReferences interopReferences, + InteropGeneratorEmitState emitState, + ModuleDefinition module) + { + TypeSignature keyType = dictionaryType.TypeArguments[0]; + TypeSignature valueType = dictionaryType.TypeArguments[1]; + TypeSignature keyAbiType = keyType.GetAbiType(interopReferences); + TypeSignature valueAbiType = valueType.GetAbiType(interopReferences); + + // Define the 'Insert' method as follows: + // + // public static bool Insert(WindowsRuntimeObjectReference objectReference, key, value) + MethodDefinition insertMethod = new( + name: "Insert"u8, + attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, + signature: MethodSignature.CreateStatic( + returnType: module.CorLibTypeFactory.Boolean, + parameterTypes: [ + interopReferences.WindowsRuntimeObjectReference.ToReferenceTypeSignature().Import(module), + keyType.Import(module), + valueType.Import(module)])) + { + NoInlining = true + }; + + // Declare the local variables: + // [0]: 'WindowsRuntimeObjectReferenceValue' (for 'thisValue') + // [1]: 'void*' (for 'thisPtr') + // [2]: 'bool' (for 'result') + CilLocalVariable loc_0_thisValue = new(interopReferences.WindowsRuntimeObjectReferenceValue.Import(module).ToValueTypeSignature()); + CilLocalVariable loc_1_thisPtr = new(module.CorLibTypeFactory.Void.MakePointerType()); + CilLocalVariable loc_2_result = new(interopReferences.CorLibTypeFactory.Boolean); + + // Jump labels + CilInstruction nop_try_this = new(Nop); + CilInstruction nop_try_key = new(Nop); + CilInstruction nop_try_value = new(Nop); + CilInstruction nop_ld_key = new(Nop); + CilInstruction nop_ld_value = new(Nop); + CilInstruction nop_finally_key = new(Nop); + CilInstruction nop_finally_value = new(Nop); + CilInstruction ldloca_0_finally_0 = new(Ldloca_S, loc_0_thisValue); + CilInstruction ldloc_2_finally_end_this = new(Ldloc_2); + + // Create a method body for the 'Insert' method + insertMethod.CilMethodBody = new CilMethodBody() + { + LocalVariables = { loc_0_thisValue, loc_1_thisPtr, loc_2_result }, + Instructions = + { + // Load the local [0] + { Ldarg_0 }, + { Callvirt, interopReferences.WindowsRuntimeObjectReferenceAsValue.Import(module) }, + { Stloc_0 }, + { nop_try_this }, + + // Arguments loading inside outer 'try/finally' block + { nop_try_key }, + { nop_try_value }, + + // 'Insert' call for the native delegate (and 'try' for local [2]) + { Ldloca_S, loc_0_thisValue }, + { Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module) }, + { Stloc_1 }, + { Ldloc_1 }, + { nop_ld_key }, + { nop_ld_value }, + { Ldloca_S, loc_2_result }, + { Conv_U }, + { Ldloc_1 }, + { Ldind_I }, + { Ldfld, vftblType.GetField("Insert"u8) }, + { Calli, WellKnownTypeSignatureFactory.IDictionary2InsertImpl(keyAbiType, valueAbiType, interopReferences).Import(module).MakeStandAloneSignature() }, + { Call, interopReferences.RestrictedErrorInfoThrowExceptionForHR.Import(module) }, + { Leave_S, ldloc_2_finally_end_this.CreateLabel() }, + + // Optional 'finally' blocks for the marshalled parameters. These are intentionally + // in reverse order, as the inner-most parameter should be released first. + { nop_finally_value }, + { nop_finally_key }, + + // 'finally' for local [0] + { ldloca_0_finally_0 }, + { Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module) }, + { Endfinally }, + + // return result; + { ldloc_2_finally_end_this }, + { Ret } + }, + ExceptionHandlers = + { + // Setup 'try/finally' for local [0] + new CilExceptionHandler + { + HandlerType = CilExceptionHandlerType.Finally, + TryStart = nop_try_this.CreateLabel(), + TryEnd = ldloca_0_finally_0.CreateLabel(), + HandlerStart = ldloca_0_finally_0.CreateLabel(), + HandlerEnd = ldloc_2_finally_end_this.CreateLabel() + } + } + }; + + // Track rewriting the two parameters for this method + emitState.TrackNativeParameterMethodRewrite( + paraneterType: keyType, + method: insertMethod, + tryMarker: nop_try_key, + loadMarker: nop_ld_key, + finallyMarker: nop_finally_key, + parameterIndex: 1); + + emitState.TrackNativeParameterMethodRewrite( + paraneterType: valueType, + method: insertMethod, + tryMarker: nop_try_value, + loadMarker: nop_ld_value, + finallyMarker: nop_finally_value, + parameterIndex: 2); + + return insertMethod; + } + + /// + /// Creates a for the Remove method for some IMaplt;K, V> interface. + /// + /// The for the type. + /// The vtable type for . + /// The instance to use. + /// The emit state for this invocation. + /// The interop module being built. + public static MethodDefinition Remove( + GenericInstanceTypeSignature dictionaryType, + TypeDefinition vftblType, + InteropReferences interopReferences, + InteropGeneratorEmitState emitState, + ModuleDefinition module) + { + TypeSignature keyType = dictionaryType.TypeArguments[0]; + TypeSignature keyAbiType = keyType.GetAbiType(interopReferences); + + // Define the 'Remove' method as follows: + // + // public static bool Remove(WindowsRuntimeObjectReference thisReference, key) + MethodDefinition removeMethod = new( + name: "Remove"u8, + attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, + signature: MethodSignature.CreateStatic( + returnType: module.CorLibTypeFactory.Boolean, + parameterTypes: [ + interopReferences.WindowsRuntimeObjectReference.Import(module).ToReferenceTypeSignature(), + keyType.Import(module)])) + { NoInlining = true }; + + // Declare the local variables: + // [0]: 'WindowsRuntimeObjectReferenceValue' (for 'thisValue') + // [1]: 'void*' (for 'thisPtr') + // [2]: 'bool' (for 'result') + CilLocalVariable loc_0_thisValue = new(interopReferences.WindowsRuntimeObjectReferenceValue.ToValueTypeSignature().Import(module)); + CilLocalVariable loc_1_thisPtr = new(module.CorLibTypeFactory.Void.MakePointerType()); + CilLocalVariable loc_2_result = new(interopReferences.CorLibTypeFactory.Boolean); + + // Jump labels + CilInstruction nop_try_this = new(Nop); + CilInstruction nop_try_key = new(Nop); + CilInstruction nop_ld_key = new(Nop); + CilInstruction nop_finally_key = new(Nop); + CilInstruction ldloca_s_0_finally_this = new(Ldloca_S, loc_0_thisValue); + CilInstruction ldloc_2_finally_end_this = new(Ldloc_2); + + // Create a method body for the 'Remove' method + removeMethod.CilMethodBody = new CilMethodBody() + { + LocalVariables = { loc_0_thisValue, loc_1_thisPtr, loc_2_result }, + Instructions = + { + // Initialize 'thisValue' + { Ldarg_0 }, + { Callvirt, interopReferences.WindowsRuntimeObjectReferenceAsValue.Import(module) }, + { Stloc_0 }, + { nop_try_this }, + + // Load the key, possibly inside a 'try/finally' block + { nop_try_key }, + + // '.try' code + { Ldloca_S, loc_0_thisValue }, + { Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module) }, + { Stloc_1 }, + { Ldloc_1 }, + { nop_ld_key }, + { Ldloca_S, loc_2_result }, + { Conv_U }, + { Ldloc_1 }, + { Ldind_I }, + { Ldfld, vftblType.GetField("Remove"u8) }, + { Calli, WellKnownTypeSignatureFactory.IDictionary2RemoveImpl(keyAbiType, interopReferences).Import(module).MakeStandAloneSignature() }, + { Call, interopReferences.RestrictedErrorInfoThrowExceptionForHR.Import(module) }, + { Leave_S, ldloc_2_finally_end_this.CreateLabel() }, + + // Optional 'finally' block for the marshalled key + { nop_finally_key }, + + // '.finally' code + { ldloca_s_0_finally_this }, + { Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module) }, + { Endfinally }, + + // return result; + { ldloc_2_finally_end_this }, + { Ret } + }, + ExceptionHandlers = + { + new CilExceptionHandler + { + HandlerType = CilExceptionHandlerType.Finally, + TryStart = nop_try_this.CreateLabel(), + TryEnd = ldloca_s_0_finally_this.CreateLabel(), + HandlerStart = ldloca_s_0_finally_this.CreateLabel(), + HandlerEnd = ldloc_2_finally_end_this.CreateLabel() + } + } + }; + + // Track rewriting the return value for this method + emitState.TrackNativeParameterMethodRewrite( + paraneterType: keyType, + method: removeMethod, + tryMarker: nop_try_key, + loadMarker: nop_ld_key, + finallyMarker: nop_finally_key, + parameterIndex: 1); + + return removeMethod; + } + } +} \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IMapViewMethods.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IMapViewMethods.cs new file mode 100644 index 000000000..eb60e9ed6 --- /dev/null +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IMapViewMethods.cs @@ -0,0 +1,273 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using AsmResolver.DotNet; +using AsmResolver.DotNet.Code.Cil; +using AsmResolver.DotNet.Signatures; +using AsmResolver.PE.DotNet.Cil; +using AsmResolver.PE.DotNet.Metadata.Tables; +using WindowsRuntime.InteropGenerator.Generation; +using WindowsRuntime.InteropGenerator.References; +using static AsmResolver.PE.DotNet.Cil.CilOpCodes; + +namespace WindowsRuntime.InteropGenerator.Factories; + +/// +internal partial class InteropMethodDefinitionFactory +{ + /// + /// Helpers for method types for constructed IMapView<K, V> interfaces. + /// + public static class IMapViewMethods + { + /// + /// Creates a for the HasKey method for some IMapView<K, V> interface. + /// + /// The for the type. + /// The vtable type for . + /// The instance to use. + /// The emit state for this invocation. + /// The interop module being built. + /// + /// This method can also be used to define the HasKey method for IMap<K, V> interfaces. + /// + public static MethodDefinition HasKey( + GenericInstanceTypeSignature readOnlyDictionaryType, + TypeDefinition vftblType, + InteropReferences interopReferences, + InteropGeneratorEmitState emitState, + ModuleDefinition module) + { + TypeSignature keyType = readOnlyDictionaryType.TypeArguments[0]; + TypeSignature keyAbiType = keyType.GetAbiType(interopReferences); + + // Define the 'HasKey' method as follows: + // + // public static bool HasKey(WindowsRuntimeObjectReference thisReference, key) + MethodDefinition hasKeyMethod = new( + name: "HasKey"u8, + attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, + signature: MethodSignature.CreateStatic( + returnType: module.CorLibTypeFactory.Boolean, + parameterTypes: [ + interopReferences.WindowsRuntimeObjectReference.Import(module).ToReferenceTypeSignature(), + keyType.Import(module)])) + { NoInlining = true }; + + // Declare the local variables: + // [0]: 'WindowsRuntimeObjectReferenceValue' (for 'thisValue') + // [1]: 'void*' (for 'thisPtr') + // [2]: 'bool' (for 'result') + CilLocalVariable loc_0_thisValue = new(interopReferences.WindowsRuntimeObjectReferenceValue.ToValueTypeSignature().Import(module)); + CilLocalVariable loc_1_thisPtr = new(module.CorLibTypeFactory.Void.MakePointerType()); + CilLocalVariable loc_2_result = new(interopReferences.CorLibTypeFactory.Boolean); + + // Jump labels + CilInstruction nop_try_this = new(Nop); + CilInstruction nop_try_key = new(Nop); + CilInstruction nop_ld_key = new(Nop); + CilInstruction nop_finally_key = new(Nop); + CilInstruction ldloca_s_0_finally_this = new(Ldloca_S, loc_0_thisValue); + CilInstruction ldloc_2_finally_end_this = new(Ldloc_2); + + // Create a method body for the 'HasKey' method + hasKeyMethod.CilMethodBody = new CilMethodBody() + { + LocalVariables = { loc_0_thisValue, loc_1_thisPtr, loc_2_result }, + Instructions = + { + // Initialize 'thisValue' + { Ldarg_0 }, + { Callvirt, interopReferences.WindowsRuntimeObjectReferenceAsValue.Import(module) }, + { Stloc_0 }, + { nop_try_this }, + + // Load the key, possibly inside a 'try/finally' block + { nop_try_key }, + + // '.try' code + { Ldloca_S, loc_0_thisValue }, + { Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module) }, + { Stloc_1 }, + { Ldloc_1 }, + { nop_ld_key }, + { Ldloca_S, loc_2_result }, + { Conv_U }, + { Ldloc_1 }, + { Ldind_I }, + { Ldfld, vftblType.GetField("HasKey"u8) }, + + // This 'calli' instruction is always using 'IReadOnlyDictionary2HasKeyImpl', but the signature for + // the vtable slot for 'HasKey' for 'IMap' is identical, so doing so is safe in this case. + { Calli, WellKnownTypeSignatureFactory.IReadOnlyDictionary2HasKeyImpl(keyAbiType, interopReferences).Import(module).MakeStandAloneSignature() }, + { Call, interopReferences.RestrictedErrorInfoThrowExceptionForHR.Import(module) }, + { Leave_S, ldloc_2_finally_end_this.CreateLabel() }, + + // Optional 'finally' block for the marshalled key + { nop_finally_key }, + + // '.finally' code + { ldloca_s_0_finally_this }, + { Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module) }, + { Endfinally }, + + // return result; + { ldloc_2_finally_end_this }, + { Ret } + }, + ExceptionHandlers = + { + new CilExceptionHandler + { + HandlerType = CilExceptionHandlerType.Finally, + TryStart = nop_try_this.CreateLabel(), + TryEnd = ldloca_s_0_finally_this.CreateLabel(), + HandlerStart = ldloca_s_0_finally_this.CreateLabel(), + HandlerEnd = ldloc_2_finally_end_this.CreateLabel() + } + } + }; + + // Track rewriting the return value for this method + emitState.TrackNativeParameterMethodRewrite( + paraneterType: keyType, + method: hasKeyMethod, + tryMarker: nop_try_key, + loadMarker: nop_ld_key, + finallyMarker: nop_finally_key, + parameterIndex: 1); + + return hasKeyMethod; + } + + /// + /// Creates a for the Lookup method for some IMapView<K, V> interface. + /// + /// The for the type. + /// The vtable type for . + /// The instance to use. + /// The emit state for this invocation. + /// The interop module being built. + /// + /// This method can also be used to define the Lookup method for IMap<K, V> interfaces. + /// + public static MethodDefinition Lookup( + GenericInstanceTypeSignature readOnlyDictionaryType, + TypeDefinition vftblType, + InteropReferences interopReferences, + InteropGeneratorEmitState emitState, + ModuleDefinition module) + { + TypeSignature keyType = readOnlyDictionaryType.TypeArguments[0]; + TypeSignature valueType = readOnlyDictionaryType.TypeArguments[1]; + TypeSignature keyAbiType = keyType.GetAbiType(interopReferences); + TypeSignature valueAbiType = valueType.GetAbiType(interopReferences); + + // Define the 'Lookup' method as follows: + // + // public static Lookup(WindowsRuntimeObjectReference thisReference, key) + MethodDefinition lookupMethod = new( + name: "Lookup"u8, + attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Static, + signature: MethodSignature.CreateStatic( + returnType: valueType.Import(module), + parameterTypes: [ + interopReferences.WindowsRuntimeObjectReference.Import(module).ToReferenceTypeSignature(), + keyType.Import(module)])) + { NoInlining = true }; + + // Declare the local variables: + // [0]: 'WindowsRuntimeObjectReferenceValue' (for 'thisValue') + // [1]: 'void*' (for 'thisPtr') + // [2]: (for 'resultNative') + CilLocalVariable loc_0_thisValue = new(interopReferences.WindowsRuntimeObjectReferenceValue.ToValueTypeSignature().Import(module)); + CilLocalVariable loc_1_thisPtr = new(module.CorLibTypeFactory.Void.MakePointerType()); + CilLocalVariable loc_2_resultNative = new(valueAbiType.Import(module)); + + // Jump labels + CilInstruction nop_try_this = new(Nop); + CilInstruction nop_try_key = new(Nop); + CilInstruction nop_ld_key = new(Nop); + CilInstruction nop_finally_key = new(Nop); + CilInstruction ldloca_s_0_finally_this = new(Ldloca_S, loc_0_thisValue); + CilInstruction nop_finally_end_this = new(Nop); + CilInstruction nop_returnValueRewrite = new(Nop); + + // Create a method body for the 'Lookup' method + lookupMethod.CilMethodBody = new CilMethodBody() + { + LocalVariables = { loc_0_thisValue, loc_1_thisPtr, loc_2_resultNative }, + Instructions = + { + // Initialize 'thisValue' + { Ldarg_0 }, + { Callvirt, interopReferences.WindowsRuntimeObjectReferenceAsValue.Import(module) }, + { Stloc_0 }, + { nop_try_this }, + + // Load the key, possibly inside a 'try/finally' block + { nop_try_key }, + + // '.try' code + { Ldloca_S, loc_0_thisValue }, + { Call, interopReferences.WindowsRuntimeObjectReferenceValueGetThisPtrUnsafe.Import(module) }, + { Stloc_1 }, + { Ldloc_1 }, + { nop_ld_key }, + { Ldloca_S, loc_2_resultNative }, + { Conv_U }, + { Ldloc_1 }, + { Ldind_I }, + { Ldfld, vftblType.GetField("Lookup"u8) }, + + // This 'calli' instruction is always using 'IReadOnlyDictionary2LookupImpl', but the signature for + // the vtable slot for 'HasKey' for 'IMap' is identical, so doing so is safe in this case. + { Calli, WellKnownTypeSignatureFactory.IReadOnlyDictionary2LookupImpl(keyAbiType, valueAbiType, interopReferences).Import(module).MakeStandAloneSignature() }, + { Call, interopReferences.RestrictedErrorInfoThrowExceptionForHR.Import(module) }, + { Leave_S, nop_finally_end_this.CreateLabel() }, + + // Optional 'finally' block for the marshalled key + { nop_finally_key }, + + // '.finally' code + { ldloca_s_0_finally_this }, + { Call, interopReferences.WindowsRuntimeObjectReferenceValueDispose.Import(module) }, + { Endfinally }, + + // Marshal and return the result + { nop_finally_end_this }, + { nop_returnValueRewrite } + }, + ExceptionHandlers = + { + new CilExceptionHandler + { + HandlerType = CilExceptionHandlerType.Finally, + TryStart = nop_try_this.CreateLabel(), + TryEnd = ldloca_s_0_finally_this.CreateLabel(), + HandlerStart = ldloca_s_0_finally_this.CreateLabel(), + HandlerEnd = nop_finally_end_this.CreateLabel() + } + } + }; + + // Track rewriting the 'key' parameter for this method + emitState.TrackNativeParameterMethodRewrite( + paraneterType: keyType, + method: lookupMethod, + tryMarker: nop_try_key, + loadMarker: nop_ld_key, + finallyMarker: nop_finally_key, + parameterIndex: 1); + + // Track rewriting the return value for this method + emitState.TrackReturnValueMethodRewrite( + returnType: valueType, + method: lookupMethod, + marker: nop_returnValueRewrite, + source: loc_2_resultNative); + + return lookupMethod; + } + } +} \ No newline at end of file diff --git a/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IVectorViewMethods.cs b/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IVectorViewMethods.cs index 33c7868e1..2b406f5ba 100644 --- a/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IVectorViewMethods.cs +++ b/src/WinRT.Interop.Generator/Factories/InteropMethodDefinitionFactory.IVectorViewMethods.cs @@ -39,6 +39,7 @@ public static MethodDefinition GetAt( ModuleDefinition module) { TypeSignature elementType = readOnlyListType.TypeArguments[0]; + TypeSignature elementAbiType = elementType.GetAbiType(interopReferences); // Define the 'GetAt' method as follows: // @@ -59,7 +60,7 @@ public static MethodDefinition GetAt( // [2]: '' (the ABI type for the type argument) CilLocalVariable loc_0_thisValue = new(interopReferences.WindowsRuntimeObjectReferenceValue.ToValueTypeSignature().Import(module)); CilLocalVariable loc_1_thisPtr = new(module.CorLibTypeFactory.Void.MakePointerType()); - CilLocalVariable loc_2_resultNative = new(elementType.GetAbiType(interopReferences).Import(module)); + CilLocalVariable loc_2_resultNative = new(elementAbiType.Import(module)); // Jump labels CilInstruction ldloca_s_0_tryStart = new(Ldloca_S, loc_0_thisValue); @@ -85,13 +86,14 @@ public static MethodDefinition GetAt( { Ldloc_1 }, { Ldarg_1 }, { Ldloca_S, loc_2_resultNative }, + { Conv_U }, { Ldloc_1 }, { Ldind_I }, { Ldfld, vftblType.GetField("GetAt"u8) }, // This 'calli' instruction is always using 'IReadOnlyList1GetAtImpl', but the signature for // the vtable slot for 'GetAt' for 'IVector' is identical, so doing so is safe in this case. - { Calli, WellKnownTypeSignatureFactory.IReadOnlyList1GetAtImpl(elementType, interopReferences).Import(module).MakeStandAloneSignature() }, + { Calli, WellKnownTypeSignatureFactory.IReadOnlyList1GetAtImpl(elementAbiType, interopReferences).Import(module).MakeStandAloneSignature() }, { Call, interopReferences.RestrictedErrorInfoThrowExceptionForHR.Import(module) }, { Leave_S, nop_finallyEnd.CreateLabel() }, diff --git a/src/WinRT.Interop.Generator/Factories/WellKnownTypeDefinitionFactory.cs b/src/WinRT.Interop.Generator/Factories/WellKnownTypeDefinitionFactory.cs index 004602fed..2bacdf01d 100644 --- a/src/WinRT.Interop.Generator/Factories/WellKnownTypeDefinitionFactory.cs +++ b/src/WinRT.Interop.Generator/Factories/WellKnownTypeDefinitionFactory.cs @@ -519,18 +519,18 @@ public static TypeDefinition IList1Vftbl( // public delegate* unmanaged[MemberFunction] GetIids; // public delegate* unmanaged[MemberFunction] GetRuntimeClassName; // public delegate* unmanaged[MemberFunction] GetTrustLevel; - // public delegate* unmanaged[MemberFunction] GetAt; + // public delegate* unmanaged[MemberFunction]*, HRESULT> GetAt; // public delegate* unmanaged[MemberFunction] get_Size; // public delegate* unmanaged[MemberFunction] GetView; - // public delegate* unmanaged[MemberFunction] IndexOf; - // public delegate* unmanaged[MemberFunction] SetAt; - // public delegate* unmanaged[MemberFunction] InsertAt; + // public delegate* unmanaged[MemberFunction], uint*, bool*, HRESULT> IndexOf; + // public delegate* unmanaged[MemberFunction], HRESULT> SetAt; + // public delegate* unmanaged[MemberFunction], HRESULT> InsertAt; // public delegate* unmanaged[MemberFunction] RemoveAt; - // public delegate* unmanaged[MemberFunction] Append; + // public delegate* unmanaged[MemberFunction], HRESULT> Append; // public delegate* unmanaged[MemberFunction] RemoveAtEnd; // public delegate* unmanaged[MemberFunction] Clear; - // public delegate* unmanaged[MemberFunction] GetMany; - // public delegate* unmanaged[MemberFunction] ReplaceAll; + // public delegate* unmanaged[MemberFunction]*, uint*, HRESULT> GetMany; + // public delegate* unmanaged[MemberFunction]*, HRESULT> ReplaceAll; vftblType.Fields.Add(new FieldDefinition("QueryInterface"u8, FieldAttributes.Public, queryInterfaceType.Import(module).MakeFunctionPointerType())); vftblType.Fields.Add(new FieldDefinition("AddRef"u8, FieldAttributes.Public, addRefType.Import(module).MakeFunctionPointerType())); vftblType.Fields.Add(new FieldDefinition("Release"u8, FieldAttributes.Public, releaseType.Import(module).MakeFunctionPointerType())); @@ -622,9 +622,9 @@ public static TypeDefinition IReadOnlyDictionary2Vftbl( // public delegate* unmanaged[MemberFunction] GetIids; // public delegate* unmanaged[MemberFunction] GetRuntimeClassName; // public delegate* unmanaged[MemberFunction] GetTrustLevel; - // public delegate* unmanaged[MemberFunction] Lookup; + // public delegate* unmanaged[MemberFunction], *, HRESULT> Lookup; // public delegate* unmanaged[MemberFunction] get_Size; - // public delegate* unmanaged[MemberFunction] HasKey; + // public delegate* unmanaged[MemberFunction], bool*, HRESULT> HasKey; // public delegate* unmanaged[MemberFunction] Split; vftblType.Fields.Add(new FieldDefinition("QueryInterface"u8, FieldAttributes.Public, queryInterfaceType.Import(module).MakeFunctionPointerType())); vftblType.Fields.Add(new FieldDefinition("AddRef"u8, FieldAttributes.Public, addRefType.Import(module).MakeFunctionPointerType())); @@ -712,12 +712,12 @@ public static TypeDefinition IDictionary2Vftbl( // public delegate* unmanaged[MemberFunction] GetIids; // public delegate* unmanaged[MemberFunction] GetRuntimeClassName; // public delegate* unmanaged[MemberFunction] GetTrustLevel; - // public delegate* unmanaged[MemberFunction] Lookup; + // public delegate* unmanaged[MemberFunction], *, HRESULT> Lookup; // public delegate* unmanaged[MemberFunction] get_Size; - // public delegate* unmanaged[MemberFunction] HasKey; + // public delegate* unmanaged[MemberFunction], bool*, HRESULT> HasKey; // public delegate* unmanaged[MemberFunction] GetView; - // public delegate* unmanaged[MemberFunction] Insert; - // public delegate* unmanaged[MemberFunction] Remove; + // public delegate* unmanaged[MemberFunction], , bool*, HRESULT> Insert; + // public delegate* unmanaged[MemberFunction], HRESULT> Remove; // public delegate* unmanaged[MemberFunction] Clear; vftblType.Fields.Add(new FieldDefinition("QueryInterface"u8, FieldAttributes.Public, queryInterfaceType.Import(module).MakeFunctionPointerType())); vftblType.Fields.Add(new FieldDefinition("AddRef"u8, FieldAttributes.Public, addRefType.Import(module).MakeFunctionPointerType())); diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs index f7c17fd92..fff810735 100644 --- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs +++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs @@ -942,6 +942,7 @@ private static void DefineIReadOnlyDictionaryTypes( readOnlyDictionaryType: typeSignature, vftblType: vftblType, interopReferences: interopReferences, + emitState: emitState, module: module, mapViewMethodsType: out TypeDefinition mapViewMethodsType);