From f2f6236ac1f0e7341f2988300b33757c7769f1e5 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 16 Apr 2026 16:08:07 -0500 Subject: [PATCH 1/5] Remove $(AndroidGenerateJniMarshalMethods) support Delete the jnimarshalmethod-gen tool, Java.Interop.Export library, Java.Interop.Export-Tests, and Java.Interop.Tools.Expressions projects. All public APIs in Java.Interop.dll (JniMarshalMemberBuilder, CreationOptions.UseMarshalMemberBuilder, etc.) are retained but marked [Obsolete] with no-op implementations. Runtime code in JreTypeManager, ManagedValueManager, and MonoRuntimeValueManager is simplified to remove MarshalMemberBuilder fallback paths. NativeAOT samples, Makefile, and CI pipeline are updated accordingly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Java.Interop.sln | 38 +- Makefile | 26 - .../automation/templates/core-tests.yaml | 43 - .../Hello-NativeAOTFromAndroid.csproj | 5 - .../Hello-NativeAOTFromAndroid.targets | 25 - .../JavaInteropRuntime.cs | 1 - .../Hello-NativeAOTFromJNI.csproj | 5 - .../Hello-NativeAOTFromJNI.targets | 24 - .../JavaCallableAttributes.cs | 32 + .../JavaInteropRuntime.cs | 1 - .../Java.Interop.Export.csproj | 25 - .../Java.Interop/MarshalMemberBuilder.cs | 545 ----------- .../Java.Interop.Tools.Expressions.csproj | 27 - .../CecilCompilerExpressionVisitor.cs | 828 ----------------- .../ExpressionAssemblyBuilder.cs | 443 --------- .../ExpressionMethodRegistration.cs | 9 - src/Java.Interop/GlobalSuppressions.cs | 1 - .../JniRuntime.JniMarshalMemberBuilder.cs | 174 +--- src/Java.Interop/Java.Interop/JniRuntime.cs | 3 - .../Java.Interop/JreTypeManager.cs | 107 +-- .../Java.Interop/ManagedValueManager.cs | 10 - .../Java.Interop/MonoRuntimeValueManager.cs | 6 +- .../Java.Runtime.Environment.csproj | 1 - .../Java.Interop/JniRuntimeTest.cs | 19 - .../Java.Interop/TestType.cs | 8 +- .../Java.Interop.Export-Tests.csproj | 41 - .../Java.Interop.Export-Tests.targets | 53 -- .../Java.Interop/ExportTest.cs | 286 ------ .../Java.Interop/JavaCallableExample.cs | 36 - .../Java.Interop/JavaCallableExampleTests.cs | 27 - .../Java.Interop/JavaVMFixture.cs | 29 - .../Java.Interop/MarshalMemberBuilderTest.cs | 570 ------------ .../java/net/dot/jni/test/ExportType.java | 162 ---- .../dot/jni/test/UseJavaCallableExample.java | 11 - ...ava.Interop.Tools.Expressions-Tests.csproj | 33 - .../ExpressionAssemblyBuilderTests.cs | 444 --------- .../Usings.cs | 1 - ...op.Tools.JavaCallableWrappers-Tests.csproj | 2 - .../Java.Interop/JavaCallableAttribute.cs | 0 .../JavaCallableConstructorAttribute.cs | 0 tools/jnimarshalmethod-gen/App.cs | 848 ------------------ tools/jnimarshalmethod-gen/Message.cs | 29 - tools/jnimarshalmethod-gen/TypeMover.cs | 549 ------------ ...oid.Tools.JniMarshalMethodGenerator.csproj | 40 - 44 files changed, 54 insertions(+), 5513 deletions(-) create mode 100644 samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.cs delete mode 100644 src/Java.Interop.Export/Java.Interop.Export.csproj delete mode 100644 src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.cs delete mode 100644 src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csproj delete mode 100644 src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.cs delete mode 100644 src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.cs delete mode 100644 src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.cs delete mode 100644 tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csproj delete mode 100644 tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targets delete mode 100644 tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.cs delete mode 100644 tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.cs delete mode 100644 tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.cs delete mode 100644 tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.cs delete mode 100644 tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.cs delete mode 100644 tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.java delete mode 100644 tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.java delete mode 100644 tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csproj delete mode 100644 tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.cs delete mode 100644 tests/Java.Interop.Tools.Expressions-Tests/Usings.cs rename {src/Java.Interop.Export => tests/Java.Interop.Tools.JavaCallableWrappers-Tests}/Java.Interop/JavaCallableAttribute.cs (100%) rename {src/Java.Interop.Export => tests/Java.Interop.Tools.JavaCallableWrappers-Tests}/Java.Interop/JavaCallableConstructorAttribute.cs (100%) delete mode 100644 tools/jnimarshalmethod-gen/App.cs delete mode 100644 tools/jnimarshalmethod-gen/Message.cs delete mode 100644 tools/jnimarshalmethod-gen/TypeMover.cs delete mode 100644 tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csproj diff --git a/Java.Interop.sln b/Java.Interop.sln index e119fb959..85f580bcc 100644 --- a/Java.Interop.sln +++ b/Java.Interop.sln @@ -1,12 +1,10 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29424.173 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{C8F58966-94BF-407F-914A-8654F8B8AE3B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.JniMarshalMethodGenerator", "tools\jnimarshalmethod-gen\Xamarin.Android.Tools.JniMarshalMethodGenerator.csproj", "{D1295A8F-4F42-461D-A046-564476C10002}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "logcat-parse", "tools\logcat-parse\logcat-parse.csproj", "{7387E151-48E3-4885-B2CA-A74434A34045}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "class-parse", "tools\class-parse\class-parse.csproj", "{38C762AB-8FD1-44DE-9855-26AAE7129DC3}" @@ -21,8 +19,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "java-interop", "src\java-in EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Dynamic", "src\Java.Interop.Dynamic\Java.Interop.Dynamic.csproj", "{AD4468F8-8883-434B-9D4C-E1801BB3B52A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Export", "src\Java.Interop.Export\Java.Interop.Export.csproj", "{B501D075-6183-4E1D-92C9-F7B5002475B1}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.JavaSource", "src\Java.Interop.Tools.JavaSource\Java.Interop.Tools.JavaSource.csproj", "{5C0B3562-8DA0-4726-9762-75B9709ED6B7}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Desktop", "Desktop", "{0998E45F-8BCE-4791-A944-962CD54E2D80}" @@ -47,8 +43,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop-Tests", "tests EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Dynamic-Tests", "tests\Java.Interop.Dynamic-Tests\Java.Interop.Dynamic-Tests.csproj", "{82B1DD53-69CA-4A61-B6B1-F06F1525EF4D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Export-Tests", "tests\Java.Interop.Export-Tests\Java.Interop.Export-Tests.csproj", "{82F24161-F0CA-44CC-AEC3-885D613605E0}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "logcat-parse-Tests", "tests\logcat-parse-Tests\logcat-parse-Tests.csproj", "{DB05D566-0BA0-4935-868D-689E2F03688E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xamarin.Android.Tools.Bytecode-Tests", "tests\Xamarin.Android.Tools.Bytecode-Tests\Xamarin.Android.Tools.Bytecode-Tests.csproj", "{C9FA4492-DEB0-4932-A6B8-E2C4E0581692}" @@ -109,10 +103,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Base", "src\Java.Base\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Base-Tests", "tests\Java.Base-Tests\Java.Base-Tests.csproj", "{CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Tools.Expressions", "src\Java.Interop.Tools.Expressions\Java.Interop.Tools.Expressions.csproj", "{1A0262FE-3CDB-4AF2-AAD8-65C59524FE8A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Tools.Expressions-Tests", "tests\Java.Interop.Tools.Expressions-Tests\Java.Interop.Tools.Expressions-Tests.csproj", "{211BAA88-66B1-41B2-88B2-530DBD8DF702}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Maven", "src\Java.Interop.Tools.Maven\Java.Interop.Tools.Maven.csproj", "{DA458F90-218B-4FE3-995F-AF4B27895FA2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Java.Interop.Tools.Maven-Tests", "tests\Java.Interop.Tools.Maven-Tests\Java.Interop.Tools.Maven-Tests.csproj", "{6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D}" @@ -125,7 +115,6 @@ EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Java.Interop.NamingCustomAttributes\Java.Interop.NamingCustomAttributes.projitems*{58b564a1-570d-4da2-b02d-25bddb1a9f4f}*SharedItemsImports = 5 - src\Java.Interop.NamingCustomAttributes\Java.Interop.NamingCustomAttributes.projitems*{d1295a8f-4f42-461d-a046-564476c10002}*SharedItemsImports = 5 src\Java.Interop.NamingCustomAttributes\Java.Interop.NamingCustomAttributes.projitems*{d18fcf91-8876-48a0-a693-2dc1e7d3d80a}*SharedItemsImports = 5 EndGlobalSection GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -133,10 +122,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D1295A8F-4F42-461D-A046-564476C10002}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D1295A8F-4F42-461D-A046-564476C10002}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D1295A8F-4F42-461D-A046-564476C10002}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D1295A8F-4F42-461D-A046-564476C10002}.Release|Any CPU.Build.0 = Release|Any CPU {7387E151-48E3-4885-B2CA-A74434A34045}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7387E151-48E3-4885-B2CA-A74434A34045}.Debug|Any CPU.Build.0 = Debug|Any CPU {7387E151-48E3-4885-B2CA-A74434A34045}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -161,10 +146,6 @@ Global {AD4468F8-8883-434B-9D4C-E1801BB3B52A}.Debug|Any CPU.Build.0 = Debug|Any CPU {AD4468F8-8883-434B-9D4C-E1801BB3B52A}.Release|Any CPU.ActiveCfg = Release|Any CPU {AD4468F8-8883-434B-9D4C-E1801BB3B52A}.Release|Any CPU.Build.0 = Release|Any CPU - {B501D075-6183-4E1D-92C9-F7B5002475B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B501D075-6183-4E1D-92C9-F7B5002475B1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B501D075-6183-4E1D-92C9-F7B5002475B1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B501D075-6183-4E1D-92C9-F7B5002475B1}.Release|Any CPU.Build.0 = Release|Any CPU {5C0B3562-8DA0-4726-9762-75B9709ED6B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5C0B3562-8DA0-4726-9762-75B9709ED6B7}.Debug|Any CPU.Build.0 = Debug|Any CPU {5C0B3562-8DA0-4726-9762-75B9709ED6B7}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -205,10 +186,6 @@ Global {82B1DD53-69CA-4A61-B6B1-F06F1525EF4D}.Debug|Any CPU.Build.0 = Debug|Any CPU {82B1DD53-69CA-4A61-B6B1-F06F1525EF4D}.Release|Any CPU.ActiveCfg = Release|Any CPU {82B1DD53-69CA-4A61-B6B1-F06F1525EF4D}.Release|Any CPU.Build.0 = Release|Any CPU - {82F24161-F0CA-44CC-AEC3-885D613605E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {82F24161-F0CA-44CC-AEC3-885D613605E0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {82F24161-F0CA-44CC-AEC3-885D613605E0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {82F24161-F0CA-44CC-AEC3-885D613605E0}.Release|Any CPU.Build.0 = Release|Any CPU {DB05D566-0BA0-4935-868D-689E2F03688E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DB05D566-0BA0-4935-868D-689E2F03688E}.Debug|Any CPU.Build.0 = Debug|Any CPU {DB05D566-0BA0-4935-868D-689E2F03688E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -321,14 +298,6 @@ Global {CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC}.Debug|Any CPU.Build.0 = Debug|Any CPU {CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC}.Release|Any CPU.ActiveCfg = Release|Any CPU {CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC}.Release|Any CPU.Build.0 = Release|Any CPU - {1A0262FE-3CDB-4AF2-AAD8-65C59524FE8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1A0262FE-3CDB-4AF2-AAD8-65C59524FE8A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1A0262FE-3CDB-4AF2-AAD8-65C59524FE8A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1A0262FE-3CDB-4AF2-AAD8-65C59524FE8A}.Release|Any CPU.Build.0 = Release|Any CPU - {211BAA88-66B1-41B2-88B2-530DBD8DF702}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {211BAA88-66B1-41B2-88B2-530DBD8DF702}.Debug|Any CPU.Build.0 = Debug|Any CPU - {211BAA88-66B1-41B2-88B2-530DBD8DF702}.Release|Any CPU.ActiveCfg = Release|Any CPU - {211BAA88-66B1-41B2-88B2-530DBD8DF702}.Release|Any CPU.Build.0 = Release|Any CPU {DA458F90-218B-4FE3-995F-AF4B27895FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {DA458F90-218B-4FE3-995F-AF4B27895FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU {DA458F90-218B-4FE3-995F-AF4B27895FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -350,14 +319,12 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {D1295A8F-4F42-461D-A046-564476C10002} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} {7387E151-48E3-4885-B2CA-A74434A34045} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} {38C762AB-8FD1-44DE-9855-26AAE7129DC3} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} {D14A1B5C-2060-4930-92BE-F7190256C735} = {C8F58966-94BF-407F-914A-8654F8B8AE3B} {94BD81F7-B06F-4295-9636-F8A3B6BDC762} = {4C173212-371D-45D8-BA83-9226194F48DC} {BB0AB9F7-0979-41A7-B7A9-877260655F94} = {4C173212-371D-45D8-BA83-9226194F48DC} {AD4468F8-8883-434B-9D4C-E1801BB3B52A} = {4C173212-371D-45D8-BA83-9226194F48DC} - {B501D075-6183-4E1D-92C9-F7B5002475B1} = {4C173212-371D-45D8-BA83-9226194F48DC} {5C0B3562-8DA0-4726-9762-75B9709ED6B7} = {0998E45F-8BCE-4791-A944-962CD54E2D80} {5887B410-D448-4257-A46B-EAC03C80BE93} = {0998E45F-8BCE-4791-A944-962CD54E2D80} {B17475BC-45A2-47A3-B8FC-62F3A0959EE0} = {0998E45F-8BCE-4791-A944-962CD54E2D80} @@ -368,7 +335,6 @@ Global {6970466B-F6D1-417A-8A27-4FED8555EBD0} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {04E28441-36FF-4964-ADD7-EFBB47CCE406} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {82B1DD53-69CA-4A61-B6B1-F06F1525EF4D} = {271C9F30-F679-4793-942B-0D9527CB3E2F} - {82F24161-F0CA-44CC-AEC3-885D613605E0} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {DB05D566-0BA0-4935-868D-689E2F03688E} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {C9FA4492-DEB0-4932-A6B8-E2C4E0581692} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {891F2E04-5614-4A26-A78F-3778025ECF43} = {271C9F30-F679-4793-942B-0D9527CB3E2F} @@ -397,8 +363,6 @@ Global {11942DE9-AEC2-4B95-87AB-CA707C37643D} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {30DCECA5-16FD-4FD0-883C-E5E83B11565D} = {0998E45F-8BCE-4791-A944-962CD54E2D80} {CB05E11B-B96F-4179-A4E9-5D6BDE29A8FC} = {271C9F30-F679-4793-942B-0D9527CB3E2F} - {1A0262FE-3CDB-4AF2-AAD8-65C59524FE8A} = {0998E45F-8BCE-4791-A944-962CD54E2D80} - {211BAA88-66B1-41B2-88B2-530DBD8DF702} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {DA458F90-218B-4FE3-995F-AF4B27895FA2} = {0998E45F-8BCE-4791-A944-962CD54E2D80} {6BC04C7F-949E-4F93-BF1F-E3B1DF0B888D} = {271C9F30-F679-4793-942B-0D9527CB3E2F} {8DB3842B-73D7-491C-96F9-EBC863E2C917} = {D5A93398-AEB1-49F3-89DC-3904A47DB0C7} diff --git a/Makefile b/Makefile index 8f31778fd..99b00c2c2 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,6 @@ NET_SUFFIX = -net7.0 TESTS = \ bin/Test$(CONFIGURATION)/Java.Interop-Tests.dll \ bin/Test$(CONFIGURATION)/Java.Interop.Dynamic-Tests.dll \ - bin/Test$(CONFIGURATION)/Java.Interop.Export-Tests.dll \ bin/Test$(CONFIGURATION)/Java.Interop.Tools.JavaCallableWrappers-Tests.dll \ bin/Test$(CONFIGURATION)/Java.Interop.Tools.JavaSource-Tests.dll \ bin/Test$(CONFIGURATION)/logcat-parse-Tests.dll \ @@ -154,31 +153,6 @@ JRE_DLL_CONFIG=bin/$(CONFIGURATION)/Java.Runtime.Environment.dll.config $(JRE_DLL_CONFIG): src/Java.Runtime.Environment/Java.Runtime.Environment.csproj $(MSBUILD) $(MSBUILD_FLAGS) $< -define run-jnimarshalmethod-gen - MONO_TRACE_LISTENER=Console.Out \ - dotnet bin/$(CONFIGURATION)$(NET_SUFFIX)/jnimarshalmethod-gen.dll $(2) $(1) -endef - -# want: /usr/local/share/dotnet/shared/Microsoft.NETCore.App/7.0.0 -# have: Microsoft.NETCore.App 7.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] -# use: shell pipeline! -SYSTEM_NET_ASSEMBLIES_PATH := $(shell dotnet --list-runtimes | grep ^Microsoft.NETCore.App | tail -1 | sed -E 's,^Microsoft.NETCore.App ([^ ]+) \[([^]]+)\]$$,\2/\1,g' ) - -run-test-jnimarshal: bin/Test$(CONFIGURATION)$(NET_SUFFIX)/Java.Interop.Export-Tests.dll bin/Test$(CONFIGURATION)$(NET_SUFFIX)/$(JAVA_INTEROP_LIB) bin/ilverify - mkdir -p test-jni-output - # Do we run w/o error? - $(call run-jnimarshalmethod-gen,"$<", -v -v -o test-jni-output --keeptemp) - (test -f test-jni-output/$(notdir $<) ) || { echo "jnimarshalmethod-gen did not create the expected assemblies in the test-jni-output directory"; exit 1; } - # Is output valid? - ikdasm test-jni-output/Java.Interop.Export-Tests.dll || { echo "output can not be processed by ikdasm"; exit 1; } - bin/ilverify test-jni-output/Java.Interop.Export-Tests.dll \ - --tokens --system-module System.Private.CoreLib -r '$(dir $<)/*.dll' \ - -r '$(SYSTEM_NET_ASSEMBLIES_PATH)/*.dll' || { echo "ilverify found issues"; exit 1; } - # replace "original" assembly - $(call run-jnimarshalmethod-gen,"$<") - # make sure tests still pass - dotnet test $< - bin/Test$(CONFIGURATION)/generator.exe: bin/$(CONFIGURATION)/generator.exe cp $<* `dirname "$@"` diff --git a/build-tools/automation/templates/core-tests.yaml b/build-tools/automation/templates/core-tests.yaml index 21764643a..ba7393dec 100644 --- a/build-tools/automation/templates/core-tests.yaml +++ b/build-tools/automation/templates/core-tests.yaml @@ -69,31 +69,6 @@ steps: condition: eq('${{ parameters.runNativeTests }}', 'true') retryCount: 1 -- template: run-dotnet-test.yaml - parameters: - testRunTitle: Java.Interop.Export (${{ parameters.platformName }}) - testAssemblyName: Java.Interop.Export-Tests - condition: or(eq('${{ parameters.runNativeDotnetTests }}', 'true'), eq('${{ parameters.runNativeTests }}', 'true')) - retryCount: 1 - -- task: DotNetCoreCLI@2 - displayName: 'jnimarshalmethod-gen Java.Interop.Export-Tests.dll' - condition: or(eq('${{ parameters.runNativeDotnetTests }}', 'true'), eq('${{ parameters.runNativeTests }}', 'true')) - inputs: - command: custom - custom: bin/$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix)/jnimarshalmethod-gen.dll - arguments: bin/Test$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix)/Java.Interop.Export-Tests.dll -v -v --keeptemp -o bin/Test$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix) - continueOnError: true - retryCountOnTaskFailure: 1 - -- template: run-dotnet-test.yaml - parameters: - testRunTitle: Java.Interop.Export (jnimarshalmethod-gen + ${{ parameters.platformName }}) - testAssemblyName: Java.Interop.Export-Tests - trxSuffix: -jnimarshalmethod - condition: or(eq('${{ parameters.runNativeDotnetTests }}', 'true'), eq('${{ parameters.runNativeTests }}', 'true')) - retryCount: 1 - - template: run-dotnet-test.yaml parameters: testRunTitle: Java.Interop-Performance ($(DotNetTargetFramework) - ${{ parameters.platformName }}) @@ -109,24 +84,6 @@ steps: condition: or(eq('${{ parameters.runNativeDotnetTests }}', 'true'), eq('${{ parameters.runNativeTests }}', 'true')) retryCount: 1 -- task: DotNetCoreCLI@2 - displayName: 'jnimarshalmethod-gen Java.Base-Tests.dll' - condition: or(eq('${{ parameters.runNativeDotnetTests }}', 'true'), eq('${{ parameters.runNativeTests }}', 'true')) - inputs: - command: custom - custom: bin/$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix)/jnimarshalmethod-gen.dll - arguments: bin/Test$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix)/Java.Base-Tests.dll -v -v --keeptemp - continueOnError: true - retryCountOnTaskFailure: 1 - -- template: run-dotnet-test.yaml - parameters: - testRunTitle: Java.Base ($(DotNetTargetFramework) - ${{ parameters.platformName }}) - testAssemblyName: Java.Base-Tests - trxSuffix: -jnimarshalmethod - condition: or(eq('${{ parameters.runNativeDotnetTests }}', 'true'), eq('${{ parameters.runNativeTests }}', 'true')) - retryCount: 1 - - task: DotNetCoreCLI@2 displayName: 'Tests: java-source-utils' inputs: diff --git a/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj b/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj index 3b9bb1d03..5923127ff 100644 --- a/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj +++ b/samples/Hello-NativeAOTFromAndroid/Hello-NativeAOTFromAndroid.csproj @@ -32,15 +32,10 @@ - - - - - - <_JnimmRefAsmDirs Include="@(RuntimePackAsset->'%(RootDir)%(Directory).'->Distinct())" /> - - - <_JnimarshalmethodGen>"$(UtilityOutputFullPath)/jnimarshalmethod-gen.dll" - <_Verbosity>-v -v --keeptemp - <_Libpath>-L "$(TargetDir)" @(_JnimmRefAsmDirs->'-L "%(Identity)"', ' ') - - - - - - - - - - - <_BuildAppApkInput Include="$(MSBuildThisFileFullPath)" /> <_BuildAppApkInput Include="app\src\main\java\**\*.java" /> @@ -181,7 +157,6 @@ <_AfterBuildDependsOnTargets> _CreateJavaCallableWrappers; - _AddMarshalMethods; diff --git a/samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.cs b/samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.cs index 74d7e21f8..f6595cdc1 100644 --- a/samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.cs +++ b/samples/Hello-NativeAOTFromAndroid/JavaInteropRuntime.cs @@ -38,7 +38,6 @@ static void init (IntPtr jnienv, IntPtr klass) var options = new JreRuntimeOptions { EnvironmentPointer = jnienv, TypeManager = new NativeAotTypeManager (), - UseMarshalMemberBuilder = false, JniGlobalReferenceLogWriter = new LogcatTextWriter (AndroidLogLevel.Debug, "NativeAot:GREF"), JniLocalReferenceLogWriter = new LogcatTextWriter (AndroidLogLevel.Debug, "NativeAot:LREF"), }; diff --git a/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj b/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj index 53822ff34..bf970f8ae 100644 --- a/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj +++ b/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.csproj @@ -21,15 +21,10 @@ - - diff --git a/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targets b/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targets index 695c22c18..e61081ce1 100644 --- a/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targets +++ b/samples/Hello-NativeAOTFromJNI/Hello-NativeAOTFromJNI.targets @@ -25,30 +25,6 @@ - - - - <_JnimmRefAsmDirs Include="@(RuntimePackAsset->'%(RootDir)%(Directory).'->Distinct())" /> - - - <_JnimarshalmethodGen>"$(UtilityOutputFullPath)/jnimarshalmethod-gen.dll" - <_Verbosity>-v -v --keeptemp - <_Libpath>-L "$(TargetDir)" @(_JnimmRefAsmDirs->'-L "%(Identity)"', ' ') - - - - - - - - - - - - - - $(DotNetTargetFramework) - enable - true - ..\..\product.snk - - - - - - $(ToolOutputFullPath) - $(JICoreLibVersion) - - - - - - - - - - - diff --git a/src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.cs b/src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.cs deleted file mode 100644 index 159db9fed..000000000 --- a/src/Java.Interop.Export/Java.Interop/MarshalMemberBuilder.cs +++ /dev/null @@ -1,545 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Reflection.Emit; -using System.Text; - -using Java.Interop.Expressions; - -namespace Java.Interop { - - [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] - [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] - public class MarshalMemberBuilder : JniRuntime.JniMarshalMemberBuilder - { - internal const string ExpressionRequiresUnreferencedCode = "System.Linq.Expression usage may trim away required code."; - - public MarshalMemberBuilder () - { - } - - public MarshalMemberBuilder (JniRuntime runtime) - { - if (runtime == null) - throw new ArgumentNullException (nameof (runtime)); - - OnSetRuntime (runtime); - } - - public override LambdaExpression CreateMarshalToManagedExpression (MethodInfo method) - { - if (method == null) - throw new ArgumentNullException (nameof (method)); - - return CreateMarshalToManagedExpression (method, null, method.DeclaringType); - } - - public override IEnumerable GetExportedMemberRegistrations (Type declaringType) - { - if (declaringType == null) - throw new ArgumentNullException ("declaringType"); - return CreateExportedMemberRegistrationIterator (declaringType); - } - - IEnumerable CreateExportedMemberRegistrationIterator (Type declaringType) - { - foreach (var method in declaringType.GetTypeInfo ().DeclaredMethods) { - var exports = (JavaCallableAttribute[]) method.GetCustomAttributes (typeof(JavaCallableAttribute), inherit:false); - if (exports == null || exports.Length == 0) - continue; - var export = exports [0]; - yield return CreateMarshalToManagedMethodRegistration (export, method, declaringType); - } - } - - public JniNativeMethodRegistration CreateMarshalToManagedMethodRegistration (JavaCallableAttribute export, MethodInfo method, Type? type = null) - { - if (export == null) - throw new ArgumentNullException ("export"); - if (method == null) - throw new ArgumentNullException ("method"); - - string signature = GetJniMethodSignature (export, method); - return new JniNativeMethodRegistration () { - Name = GetJniMethodName (export, method), - Signature = signature, - Marshaler = CreateJniMethodMarshaler (method, export, type), - }; - } - - string GetJniMethodName (JavaCallableAttribute export, MethodInfo method) - { - return "n_" + method.Name; - } - - public string GetJniMethodSignature (JavaCallableAttribute export, MethodInfo method) - { - if (export == null) - throw new ArgumentNullException ("export"); - if (method == null) - throw new ArgumentNullException ("method"); - - if (export.Signature != null) - return export.Signature; - - return export.Signature = GetJniMethodSignature (method); - } - - Delegate CreateJniMethodMarshaler (MethodInfo method, JavaCallableAttribute? export, Type? type) - { - var e = CreateMarshalToManagedExpression (method, export, type); - return e.Compile (); - } - - public LambdaExpression CreateMarshalToManagedExpression (MethodInfo method, JavaCallableAttribute? callable, Type? type = null) - { - if (method == null) - throw new ArgumentNullException ("method"); - type = type ?? method.DeclaringType; - - var methodParameters = method.GetParameters (); - - CheckMarshalTypesMatch (method, callable?.Signature, methodParameters); - - bool direct = IsDirectMethod (methodParameters); - - var jnienv = Expression.Parameter (typeof (IntPtr), direct ? methodParameters [0].Name : "__jnienv"); - var context = Expression.Parameter (typeof (IntPtr), direct ? methodParameters [1].Name : (method.IsStatic ? "__class" : "__this")); - - var envp = Expression.Variable (typeof (JniTransition), "__envp"); - var jvm = Expression.Variable (typeof (JniRuntime), "__jvm"); - var vm = Expression.Variable (typeof (JniRuntime.JniValueManager), "__vm"); - var envpVars = new List () { - envp, - jvm, - }; - - int peerableParametersCount = 0; - for (int i = 0; i < methodParameters.Length; ++i) { - var marshaler = GetParameterMarshaler (methodParameters [i]); - - if (typeof (IJavaPeerable).GetTypeInfo ().IsAssignableFrom (methodParameters [i].ParameterType.GetTypeInfo ())) - peerableParametersCount ++; - } - - bool useVmVariable = (!method.IsStatic || peerableParametersCount > 0) && !direct; - if (useVmVariable) - envpVars.Add (vm); - - var envpBody = new List () { - Expression.Assign (envp, CreateJniTransition (jnienv)), - }; - - var waitForGCBridge = typeof(JniRuntime.JniValueManager) - .GetRuntimeMethod (nameof (JniRuntime.JniValueManager.WaitForGCBridgeProcessing), new Type [0]) ?? - throw new NotSupportedException ("Could not find JniRuntime.JniValueManager.WaitForGCBridgeProcessing()"); - - var marshalBody = new List () { - Expression.Assign (jvm, GetRuntime ()), - }; - - if (useVmVariable) { - marshalBody.Add (Expression.Assign (vm, Expression.Property (jvm, "ValueManager"))); - marshalBody.Add (Expression.Call (vm, waitForGCBridge)); - } else - marshalBody.Add (Expression.Call (Expression.Property (jvm, "ValueManager"), waitForGCBridge)); - - Expression? self = null; - var marshalerContext = new JniValueMarshalerContext (jvm, useVmVariable ? vm : null); - if (!method.IsStatic) { - var selfMarshaler = Runtime.ValueManager.GetValueMarshaler (type!); - self = selfMarshaler.CreateParameterToManagedExpression (marshalerContext, context, 0, type); - } - - var marshalParameters = new List (methodParameters.Length); - var invokeParameters = new List (methodParameters.Length); - for (int i = 0; i < methodParameters.Length; ++i) { - var marshaler = GetParameterMarshaler (methodParameters [i]); - ParameterExpression np; - if (i > 1 || !direct) - np = Expression.Parameter (marshaler.MarshalType, methodParameters [i].Name); - else { - if (i == 0) - np = jnienv; - else if (i == 1) - np = context; - else - throw new InvalidOperationException ("Should not be reached."); - } - var p = marshaler.CreateParameterToManagedExpression (marshalerContext, np, methodParameters [i].Attributes, methodParameters [i].ParameterType); - marshalParameters.Add (np); - invokeParameters.Add (p); - } - - marshalBody.AddRange (marshalerContext.CreationStatements); - - Expression invoke = method.IsStatic - ? Expression.Call (method, invokeParameters) - : Expression.Call (self, method, invokeParameters); - Expression? ret = null; - if (method.ReturnType == typeof (void)) { - envpVars.AddRange (marshalerContext.LocalVariables); - - marshalBody.Add (invoke); - envpBody.Add ( - Expression.TryCatchFinally ( - Expression.Block (marshalBody), - CreateDisposeJniEnvironment (envp, marshalerContext.CleanupStatements), - CreateMarshalException (envp, jvm, null))); - } else { - var rmarshaler = GetParameterMarshaler (method.ReturnParameter); - var jniRType = rmarshaler.MarshalType; - var exit = Expression.Label (jniRType, "__exit"); - var mret = Expression.Variable (method.ReturnType, "__mret"); - envpVars.Add (mret); - marshalBody.Add (Expression.Assign (mret, invoke)); - marshalerContext.CreationStatements.Clear (); - ret = rmarshaler.CreateReturnValueFromManagedExpression (marshalerContext, mret); - marshalBody.AddRange (marshalerContext.CreationStatements); - marshalBody.Add (Expression.Return (exit, ret)); - - envpVars.AddRange (marshalerContext.LocalVariables); - - envpBody.Add ( - Expression.TryCatchFinally ( - Expression.Block (marshalBody), - CreateDisposeJniEnvironment (envp, marshalerContext.CleanupStatements), - CreateMarshalException (envp, jvm, exit))); - - envpBody.Add (Expression.Label (exit, Expression.Default (jniRType))); - } - - var funcTypeParams = new List (); - var bodyParams = new List (); - if (!direct) { - funcTypeParams.Add (typeof (IntPtr)); - funcTypeParams.Add (typeof (IntPtr)); - bodyParams.Add (jnienv); - bodyParams.Add (context); - } - foreach (var p in marshalParameters) - funcTypeParams.Add (p.Type); - var marshalerType = GetMarshalerType (ret?.Type, funcTypeParams, method.DeclaringType); - - bodyParams.AddRange (marshalParameters); - var body = Expression.Block (envpVars, envpBody); - - return marshalerType == null - ? Expression.Lambda (body, bodyParams) - : Expression.Lambda (marshalerType, body, bodyParams); - } - - // Keep in sync with ExpressionAssemblyBuilder.GetMarshalMethodDelegateType() - static Type? GetMarshalerType (Type? returnType, List funcTypeParams, Type? declaringType) - { - // Too many parameters; does a `_JniMarshal_*` type exist in the type's declaring assembly? - funcTypeParams.RemoveRange (0, 2); - var marshalDelegateName = new StringBuilder (); - marshalDelegateName.Append ("_JniMarshal_PP"); - foreach (var paramType in funcTypeParams) { - marshalDelegateName.Append (GetJniMarshalDelegateParameterIdentifier (paramType)); - } - marshalDelegateName.Append ("_"); - if (returnType == null) { - marshalDelegateName.Append ("V"); - } else { - marshalDelegateName.Append (GetJniMarshalDelegateParameterIdentifier (returnType)); - } - - Type? marshalDelegateType = declaringType?.Assembly.GetType (marshalDelegateName.ToString (), throwOnError: false); - if (marshalDelegateType != null) { - return marshalDelegateType; - } - -#if !NET - // Punt?; System.Linq.Expressions will automagically produce the needed delegate type. - // Unfortunately, this won't work with jnimarshalmethod-gen.exe. - return marshalDelegateType; -#else // NET - return CreateMarshalDelegateType (marshalDelegateName.ToString (), returnType, funcTypeParams); -#endif // NET - } - -#if NET - static object ab_lock = new object (); - static AssemblyBuilder? assemblyBuilder; - static ModuleBuilder? moduleBuilder; - static Type[]? DelegateCtorSignature; - static Dictionary? marshalDelegateTypes; - - static Type? CreateMarshalDelegateType (string name, Type? returnType, List funcTypeParams) - { - lock (ab_lock) { - if (assemblyBuilder == null) { - var aname = new AssemblyName ("jni-marshal-method-delegates"); - assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly (aname, AssemblyBuilderAccess.Run); - moduleBuilder = assemblyBuilder.DefineDynamicModule (aname.Name!); - - DelegateCtorSignature = new Type[] { - typeof (object), - typeof (IntPtr) - }; - marshalDelegateTypes = new (StringComparer.Ordinal); - } - if (marshalDelegateTypes!.TryGetValue (name, out var type)) { - return type; - } - funcTypeParams.Insert (0, typeof (IntPtr)); - funcTypeParams.Insert (0, typeof (IntPtr)); - var typeBuilder = moduleBuilder!.DefineType ( - name, - TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, - typeof (MulticastDelegate) - ); - - const MethodAttributes CtorAttributes = MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public; - const MethodImplAttributes ImplAttributes = MethodImplAttributes.Runtime | MethodImplAttributes.Managed; - const MethodAttributes InvokeAttributes = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; - - typeBuilder.DefineConstructor (CtorAttributes, CallingConventions.Standard, DelegateCtorSignature) - .SetImplementationFlags (ImplAttributes); - typeBuilder.DefineMethod ("Invoke", InvokeAttributes, returnType, funcTypeParams.ToArray ()) - .SetImplementationFlags (ImplAttributes); - var marshalDelType = typeBuilder.CreateTypeInfo (); - marshalDelegateTypes.Add (name, marshalDelType); - return marshalDelType; - } - } -#endif // NET - - static char GetJniMarshalDelegateParameterIdentifier (Type type) - { - if (type == typeof (bool)) return 'Z'; - if (type == typeof (byte)) return 'B'; - if (type == typeof (sbyte)) return 'B'; - if (type == typeof (char)) return 'C'; - if (type == typeof (short)) return 'S'; - if (type == typeof (ushort)) return 's'; - if (type == typeof (int)) return 'I'; - if (type == typeof (uint)) return 'i'; - if (type == typeof (long)) return 'J'; - if (type == typeof (ulong)) return 'j'; - if (type == typeof (float)) return 'F'; - if (type == typeof (double)) return 'D'; - if (type == typeof (void)) return 'V'; - return 'L'; - } - - void CheckMarshalTypesMatch (MethodInfo method, string? signature, ParameterInfo[] methodParameters) - { - if (signature == null) - return; - - var mptypes = JniSignature.GetMarshalParameterTypes (signature).ToList (); - int rpcount = methodParameters.Length; - int len = Math.Min (methodParameters.Length, mptypes.Count); - int start = 0; - if (IsDirectMethod (methodParameters)) { - start += 2; - rpcount -= 2; - } - for (int i = start; i < len; ++i) { - var vm = GetParameterMarshaler (methodParameters [i]); - var jni = vm.MarshalType; - if (mptypes [i] != jni) - throw new ArgumentException ( - $"JNI parameter type mismatch. Type `{jni}` != `{mptypes [i]}` at index {i} in `{signature}`.", - "signature"); - } - - if (mptypes.Count != rpcount) - throw new ArgumentException ( - string.Format ("JNI parametr count mismatch: signature contains {0} parameters, method contains {1}.", - mptypes.Count, methodParameters.Length), - nameof (signature)); - - var jrinfo = JniSignature.GetMarshalReturnType (signature); - var mrvm = GetParameterMarshaler (method.ReturnParameter); - var mrinfo = mrvm.MarshalType; - if (mrinfo != jrinfo) - throw new ArgumentException ( - string.Format ("JNI return type mismatch. Type '{0}' != '{1}'.", jrinfo, mrinfo), - nameof (signature)); - } - - static ConstructorInfo JniTransitionConstructor = - (from c in typeof (JniTransition).GetTypeInfo ().DeclaredConstructors - let p = c.GetParameters () - where p.Length == 1 && p [0].ParameterType == typeof (IntPtr) - select c) - .First (); - - static Expression CreateJniTransition (ParameterExpression jnienv) - { - return Expression.New ( - JniTransitionConstructor, - jnienv); - } - - static readonly MethodInfo JniRuntime_ExceptionShouldTransitionToJni = - typeof(JniRuntime).GetRuntimeMethod ("ExceptionShouldTransitionToJni", new[] { typeof (Exception) }) ?? - throw new NotSupportedException ("Could not find `JniRuntime.ExceptionShouldTransitionToJni()`"); - static readonly MethodInfo JniTransition_SetPendingException = - ((Action) (new JniTransition ().SetPendingException)).Method; - - static CatchBlock CreateMarshalException (ParameterExpression envp, ParameterExpression jvm, LabelTarget? exit) - { - var ex = Expression.Variable (typeof (Exception), "__e"); - var body = new List () { - Expression.Call (envp, JniTransition_SetPendingException, ex), - }; - if (exit != null) { - body.Add (Expression.Return (exit, Expression.Default (exit.Type))); - } - var filter = Expression.Call (jvm, JniRuntime_ExceptionShouldTransitionToJni, ex); - return Expression.Catch (ex, Expression.Block (body), filter); - } - - static readonly MethodInfo JniTransition_Dispose = ((Action) (new JniTransition ().Dispose)).Method; - - static Expression CreateDisposeJniEnvironment (ParameterExpression envp, IList cleanup) - { - var disposeTransition = Expression.Call (envp, JniTransition_Dispose); - return Expression.Block ( - cleanup.Reverse ().Concat (new[]{ disposeTransition }));; - } - - static Expression GetRuntime () - { - return Expression.Property (null, typeof (JniEnvironment), "Runtime"); - } - - static MethodInfo FormatterServices_GetUninitializedObject = -#if NETCOREAPP - ((Func) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject) -#else // !NETCOREAPP - ((Func) System.Runtime.Serialization.FormatterServices.GetUninitializedObject) -#endif // NETCOREAPP - .Method; - static MethodInfo IJavaPeerable_SetPeerReference = - typeof (IJavaPeerable).GetRuntimeMethod ("SetPeerReference", new[]{typeof (JniObjectReference)}) ?? - throw new NotSupportedException ("Could not find IJavaPeerable.SetPeerReference()!"); - - public override Expression> CreateConstructActivationPeerExpression (ConstructorInfo constructor) - { - if (constructor == null) - throw new ArgumentNullException (nameof (constructor)); - - Func mbi = constructor.Invoke; - - var c = Expression.Parameter (typeof (ConstructorInfo), "constructor"); - var r = Expression.Parameter (typeof (JniObjectReference), "reference"); - var p = Expression.Parameter (typeof (object[]), "parameters"); - - var t = Expression.Variable (typeof (Type), "type"); - var s = Expression.Variable (typeof (object), "self"); - var b = Expression.Block ( - new []{t, s}, - Expression.Assign (t, Expression.Property (c, "DeclaringType")), - Expression.Assign (s, Expression.Call (FormatterServices_GetUninitializedObject, t)), - Expression.Call (Expression.Convert (s, typeof (IJavaPeerable)), IJavaPeerable_SetPeerReference, r), - Expression.Call (c, mbi.GetMethodInfo (), s, p), - s); - return Expression.Lambda> (b, new []{c, r, p}); - } - - public static string GetMarshalMethodName (string name, string signature) - { - if (name == null) - throw new ArgumentNullException (nameof (name)); - - if (signature == null) - throw new ArgumentNullException (nameof (signature)); - - var idx1 = signature.IndexOf ('('); - var idx2 = signature.IndexOf (')'); - var arguments = signature; - - if (idx1 >= 0 && idx2 >= idx1) - arguments = arguments.Substring (idx1 + 1, idx2 - idx1 - 1); - - return $"n_{name}{(string.IsNullOrEmpty (arguments) ? "" : "_")}{arguments?.Replace ('/', '_')?.Replace (';', '_')}"; - } - } - - static class JniSignature { - - public static Type? GetMarshalReturnType (string signature) - { - int idx = signature.LastIndexOf (')') + 1; - return ExtractMarshalTypeFromSignature (signature, ref idx); - } - - public static IEnumerable GetMarshalParameterTypes (string signature) - { - if (signature.StartsWith ("(", StringComparison.Ordinal)) { - int e = signature.IndexOf (")", StringComparison.Ordinal); - signature = signature.Substring (1, e >= 0 ? e-1 : signature.Length-1); - } - int i = 0; - Type? t; - while ((t = ExtractMarshalTypeFromSignature (signature, ref i)) != null) - yield return t; - } - - // as per: http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/types.html - static Type? ExtractMarshalTypeFromSignature (string signature, ref int index) - { - #if false - if (index >= signature.Length) - return null; - var i = index++; - switch (signature [i]) { - case 'B': return typeof (sbyte); - case 'C': return typeof (char); - case 'D': return typeof (double); - case 'F': return typeof (float); - case 'I': return typeof (int); - case 'J': return typeof (long); - case 'S': return typeof (short); - case 'V': return typeof (void); - case 'Z': return typeof (bool); - case '[': - case 'L': return typeof (IntPtr); - default: - throw new ArgumentException ("Unknown JNI Type '" + signature [i] + "' within: " + signature, "signature"); - } - #else - if (index >= signature.Length) - return null; - var i = index++; - switch (signature [i]) { - case 'B': return typeof (sbyte); - case 'C': return typeof (char); - case 'D': return typeof (double); - case 'F': return typeof (float); - case 'I': return typeof (int); - case 'J': return typeof (long); - case 'S': return typeof (short); - case 'V': return typeof (void); - case 'Z': return typeof (bool); - case '[': - ++i; - if (i >= signature.Length) - throw new ArgumentException ("Missing array type after '[' at index " + i + " in: " + signature, "signature"); - ExtractMarshalTypeFromSignature (signature, ref index); - return typeof (IntPtr); - case 'L': { - var e = signature.IndexOf (";", index, StringComparison.Ordinal); - if (e <= 0) - throw new ArgumentException ("Missing reference type after 'L' at index " + i + "in: " + signature, "signature"); - index = e + 1; - return typeof (IntPtr); - } - default: - throw new ArgumentException ("Unknown JNI Type '" + signature [i] + "' within: " + signature, "signature"); - } - #endif - } - } -} - diff --git a/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csproj b/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csproj deleted file mode 100644 index b8b67337b..000000000 --- a/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - - $(DotNetTargetFramework) - enable - enable - - - - - - $(UtilityOutputFullPath) - - - - - - - - - - - - - - - diff --git a/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.cs b/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.cs deleted file mode 100644 index cbfdc6756..000000000 --- a/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/CecilCompilerExpressionVisitor.cs +++ /dev/null @@ -1,828 +0,0 @@ -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Linq.Expressions; - -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace Java.Interop.Tools.Expressions; - -class CecilCompilerExpressionVisitor : ExpressionVisitor -{ - public CecilCompilerExpressionVisitor (AssemblyDefinition declaringAssembly, MethodBody body, VariableDefinitions variables, Action logger) - { - this.assemblyDef = declaringAssembly; - this.body = body; - this.variables = variables; - il = body.GetILProcessor (); - Logger = logger; - } - - AssemblyDefinition assemblyDef; - MethodBody body; - ILProcessor il; - VariableDefinitions variables; - Dictionary> returnFixups = new (); - Action Logger; - - /// - /// Dispatches the expression to one of the more specialized visit methods in this class. - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - [return: NotNullIfNotNull("node")] - public override Expression? Visit ( - Expression? node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.Visit [{node?.NodeType.ToString () ?? ""}]: {node}"); - return base.Visit (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitBinary ( - BinaryExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitBinary: {node} [{node.NodeType}]"); - switch (node.NodeType) { - case ExpressionType.Assign: - var target = node.Left as ParameterExpression; - if (target == null) { - Logger (TraceLevel.Verbose, $"# jonp: don't know where to assign `{node.Left}`!"); - return base.VisitBinary (node); - } - Logger (TraceLevel.Verbose, $"# jonp: target={target}; target.Type={target.Type}; requires-&? {InstanceInvokeRequiresAddress (target.Type)}"); - if (InstanceInvokeRequiresAddress (target.Type) && node.Right is NewExpression n) { - variables [target].LoadAddress (il); - Visit (node.Right); - } else { - Visit (node.Right); - variables [target].Store (il); - } - break; - case ExpressionType.Equal: - Visit (node.Left); - Visit (node.Right); - il.Emit (OpCodes.Ceq); - break; - default: - Logger (TraceLevel.Verbose, $"# jonp: don't know how to emit binary expr {node.NodeType}!"); - base.VisitBinary (node); - break; - } - return node; - } - - static bool InstanceInvokeRequiresAddress (Type type) => type.IsValueType && !type.IsPrimitive; - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitBlock ( - BlockExpression node) - { - // Base method also visits parameter nodes after body; we don't want that. - // https://cs.github.com/dotnet/runtime/blob/9df6ea21007319967975dc9985413bb6518287da/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/ExpressionVisitor.cs#L214 - // return base.VisitBlock (node); - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitBlock: {node}"); - foreach (var e in node.Expressions) { - Visit (e); - } - return node; - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitConditional ( - ConditionalExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitConditional: {node}"); - Visit (node.Test); - var startFalse = il.Create (OpCodes.Nop); - var endBranch = il.Create (OpCodes.Nop); - il.Emit (OpCodes.Brfalse, startFalse); - Visit (node.IfTrue); - il.Emit (OpCodes.Br, endBranch); - il.Append (startFalse); - Visit (node.IfFalse); - il.Append (endBranch); - return node; - // return base.VisitConditional (node); - } - - /// - /// Visits the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitConstant ( - ConstantExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitConstant: {node}"); - switch (Type.GetTypeCode (node.Type)) { - case TypeCode.String: - il.Emit (OpCodes.Ldstr, (string?) node.Value); - break; - case TypeCode.Boolean: - if ((bool) node.Value!) { - il.Emit (OpCodes.Ldc_I4_1); - } else { - il.Emit (OpCodes.Ldc_I4_0); - } - break; - case TypeCode.Char: - il.Emit (OpCodes.Ldc_I4, (char) node.Value!); - break; - case TypeCode.SByte: - il.Emit (OpCodes.Ldc_I4_S, (sbyte) node.Value!); - break; - case TypeCode.Byte: - il.Emit (OpCodes.Ldc_I4, (byte) node.Value!); - break; - case TypeCode.Int16: - il.Emit (OpCodes.Ldc_I4, (short) node.Value!); - break; - case TypeCode.Int32: - il.Emit (OpCodes.Ldc_I4, (int) node.Value!); - break; - case TypeCode.Int64: - il.Emit (OpCodes.Ldc_I8, (long) node.Value!); - break; - case TypeCode.Single: - il.Emit (OpCodes.Ldc_R4, (float) node.Value!); - break; - case TypeCode.Double: - il.Emit (OpCodes.Ldc_R8, (double) node.Value!); - break; - case TypeCode.UInt16: - il.Emit (OpCodes.Ldc_I4, (short) node.Value!); - break; - case TypeCode.UInt32: - il.Emit (OpCodes.Ldc_I4, (int) node.Value!); - break; - case TypeCode.UInt64: - il.Emit (OpCodes.Ldc_I8, (int) node.Value!); - break; - case TypeCode.Object: - if (node.Type == typeof (Type)) { - Logger (TraceLevel.Verbose, $"# jonp: TODO load type {node.Value}"); - break; - } else if (node.Value == null) { - Logger (TraceLevel.Verbose, $"# jonp: TODO ldnull {node.Value}"); - il.Emit (OpCodes.Ldnull); - break; - } - goto default; - default: - Logger (TraceLevel.Verbose, $"# jonp: don't know how to deal with constant with value `{node}` NodeType `{node.NodeType}` Type `{node.Type}` typecode {Type.GetTypeCode (node.Type)}"); - break; - // throw new NotSupportedException (); - } - return node; - } - - /// - /// Visits the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitDebugInfo ( - DebugInfoExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitDebugInfo: {node}"); - return base.VisitDebugInfo (node); - } - - /// - /// Visits the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitDefault ( - DefaultExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitDefault: {node}"); - return base.VisitDefault (node); - } - - /// - /// Visits the children of the extension expression. - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - /// - /// This can be overridden to visit or rewrite specific extension nodes. - /// If it is not overridden, this method will call , - /// which gives the node a chance to walk its children. By default, - /// will try to reduce the node. - /// - protected override Expression VisitExtension ( - Expression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitExtension: {node}"); - return base.VisitExtension (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitGoto ( - GotoExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitGoto: {node}"); - if (node.Kind != GotoExpressionKind.Return || node.Type == typeof (void)) { - return base.VisitGoto (node); - } - Visit (node.Value); - variables.ReturnValue?.Store (il); - il.Emit (OpCodes.Ret); - List fixups = GetFixupsForLabelTarget (node.Target); - fixups.Add (il.Body.Instructions.Last ()); - Logger (TraceLevel.Verbose, $"# jonp: adding fixup for goto `{node}` at index {il.Body.Instructions.Count-1}"); - return node; - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitInvocation ( - InvocationExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitInvocation: {node}"); - return base.VisitInvocation (node); - } - - /// - /// Visits the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - [return: NotNullIfNotNull("node")] - protected override LabelTarget? VisitLabelTarget ( - LabelTarget? node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitLabelTarget: {node}"); - if (node != null) { - il.Emit (OpCodes.Nop); - GetFixupsForLabelTarget (node).Add (il.Body.Instructions.Last ()); - } - return base.VisitLabelTarget (node); - } - - List GetFixupsForLabelTarget (LabelTarget target) - { - if (!returnFixups.TryGetValue (target, out List? fixups)) { - returnFixups.Add (target, fixups = new ()); - } - return fixups; - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitLabel ( - LabelExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitLabel: {node}"); - var target = il.Body.Instructions.Last (); - if (returnFixups.TryGetValue (node.Target, out List? fixups)) { - foreach (var replace in fixups) { - Logger (TraceLevel.Verbose, $"# jonp: VisitLabel: replacing instruction `{replace}` w/ `leave {target}"); - Debug.Assert (replace.OpCode == OpCodes.Ret || replace.OpCode == OpCodes.Nop); - replace.OpCode = OpCodes.Leave; - replace.Operand = target; - } - } - return base.VisitLabel (node); - } - - /// - /// Visits the children of the . - /// - /// The type of the delegate. - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitLambda(Expression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitLambda: {node}"); - return Visit (node.Body); - // Base method also visits parameter nodes after body; we don't want that. - // return base.VisitLambda (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitLoop ( - LoopExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitLoop: {node}"); - return base.VisitLoop (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitMember ( - MemberExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitMember: {node}"); - base.VisitMember (node); - switch (node.Member.MemberType) { - case System.Reflection.MemberTypes.Field: - var field = (System.Reflection.FieldInfo) node.Member; - il.Emit ( - field.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld, - assemblyDef.MainModule.ImportReference (field)); - break; - case System.Reflection.MemberTypes.Property: - var property = (System.Reflection.PropertyInfo) node.Member; - var getter = property.GetGetMethod (); - il.Emit (GetCallOpCode (getter!), assemblyDef.MainModule.ImportReference (getter)); - break; - default: - throw new NotSupportedException ($"How do I visit `{node.Member.MemberType}`? {node}"); - } - return node; - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitIndex ( - IndexExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitIndex: {node}"); - return base.VisitIndex (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitMethodCall ( - MethodCallExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitMethodCall: {node}; node.Object={node.Object}"); - // We need to special-case `node.Object` handling - // https://github.com/dotnet/runtime/blob/edd23fcb1b350cb1a53fa409200da55e9c33e99e/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/ExpressionVisitor.cs#L403-L413 - - if (node.Object is ParameterExpression target) { - if (InstanceInvokeRequiresAddress (target.Type)) { - variables [target].LoadAddress (il); - } else { - variables [target].Load (il); - } - } else { - Visit (node.Object); - } - foreach (var a in node.Arguments) { - Visit (a); - } - il.Emit (GetCallOpCode (node.Method), assemblyDef.MainModule.ImportReference (node.Method)); - - return node; - } - - OpCode GetCallOpCode (global::System.Reflection.MethodBase method) - { - if (method.IsStatic || (method.DeclaringType?.IsValueType ?? false)) - return OpCodes.Call; - return OpCodes.Callvirt; - } - - void EmitConsoleWriteLine (ILProcessor il, string message) - { - Action cwl = Console.WriteLine; - il.Emit (OpCodes.Ldstr, message); - il.Emit (OpCodes.Call, assemblyDef.MainModule.ImportReference (cwl.Method)); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitNewArray ( - NewArrayExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitNewArray: {node}"); - return base.VisitNewArray (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitNew ( - NewExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitNew: {node}"); - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitNew: ctor={node.Constructor} {node.Constructor != null}"); - base.VisitNew (node); - if (node.Constructor == null && node.Type.IsValueType) { - il.Emit (OpCodes.Initobj, assemblyDef.MainModule.ImportReference (node.Type)); - } else if (node.Type.IsValueType) { - il.Emit (OpCodes.Call, assemblyDef.MainModule.ImportReference (node.Constructor)); - } else { - il.Emit (OpCodes.Newobj, assemblyDef.MainModule.ImportReference (node.Constructor)); - } - return node; - } - - /// - /// Visits the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitParameter ( - ParameterExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitParameter: {(node.Type.IsByRef ? "&" : "")}{node}"); - - if (node.Type.IsByRef) { - variables [node].LoadAddress (il); - } else { - variables [node].Load (il); - } - - return node; - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitRuntimeVariables ( - RuntimeVariablesExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitRuntimeVariables: {node}"); - return base.VisitRuntimeVariables (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override SwitchCase VisitSwitchCase ( - SwitchCase node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitSwitchCase: {node}"); - return base.VisitSwitchCase (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitSwitch ( - SwitchExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitSwitch: {node}"); - return base.VisitSwitch (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override CatchBlock VisitCatchBlock ( - CatchBlock node) - { - // On entry, IL stream should assume that there is an Exception type on the evaluation stack. - - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitCatchBlock: {node}"); - - var startCatchBlock = il.Body.Instructions.Count; - var handlerDef = new ExceptionHandler (ExceptionHandlerType.Catch) { - TryStart = TryStart, - }; - body.ExceptionHandlers.Add (handlerDef); - - if (node.Filter != null) { - EmitCatchFilter (node); - handlerDef.HandlerType = ExceptionHandlerType.Filter; - handlerDef.FilterStart = il.Body.Instructions [startCatchBlock]; - startCatchBlock = il.Body.Instructions.Count; - } else if (node.Test != null) { - handlerDef.CatchType = assemblyDef.MainModule.ImportReference (node.Test); - } - - if (node.Variable != null) { - il.Emit (OpCodes.Castclass, assemblyDef.MainModule.ImportReference (node.Variable.Type)); - variables [node.Variable!].Store (il); - } else { - il.Emit (OpCodes.Pop); - } - - Visit (node.Body); - EmitLeave (); - - handlerDef.HandlerStart = il.Body.Instructions [startCatchBlock]; - - return node; - } - - void EmitCatchFilter (CatchBlock node) - { - Instruction? fixupStartFilter = null; - Instruction? fixupEndFilter = null; - - if (node.Test != null) { - il.Emit (OpCodes.Isinst, assemblyDef.MainModule.ImportReference (node.Test)); - il.Emit (OpCodes.Dup); - il.Emit (OpCodes.Brtrue_S, il.Body.Instructions.Last ()); - fixupStartFilter = il.Body.Instructions.Last (); - il.Emit (OpCodes.Pop); - il.Emit (OpCodes.Ldc_I4_0); - il.Emit (OpCodes.Br_S, il.Body.Instructions.Last ()); - fixupEndFilter = il.Body.Instructions.Last (); - } - - if (node.Variable != null) { - variables [node.Variable!].Store (il); - } else { - il.Emit (OpCodes.Pop); - } - - if (fixupStartFilter != null) { - fixupStartFilter.Operand = il.Body.Instructions.Last (); - } - - Visit (node.Filter); - - // node.Filter is assumed to leave a "boolean" on the eval stack; convert to an int - il.Emit (OpCodes.Ldc_I4_0); - il.Emit (OpCodes.Cgt_Un); - - il.Emit (OpCodes.Endfilter); - - if (fixupEndFilter != null) { - fixupEndFilter.Operand = il.Body.Instructions.Last (); - } - } - - Instruction? TryStart; - List? FixupLeaveOffsets; - - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitTry ( - TryExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitTry: {node}"); - - var prevTryStart = TryStart; - var pFixupLeaveOffsets = FixupLeaveOffsets; - try { - var startTryBlock = il.Body.Instructions.Count; - FixupLeaveOffsets = new (); - - Visit (node.Body); - EmitLeave (); - TryStart = il.Body.Instructions [startTryBlock]; - - Visit (node.Handlers, VisitCatchBlock); - - if (node.Finally != null) { - var startFinallyBlock = il.Body.Instructions.Count; - Visit (node.Finally); - il.Emit (OpCodes.Endfinally); - - var finallyDef = new ExceptionHandler (ExceptionHandlerType.Finally) { - TryStart = TryStart, - HandlerStart = il.Body.Instructions [startFinallyBlock], - }; - body.ExceptionHandlers.Add (finallyDef); - } - - // Visit (node.Fault); - - // ECMA 335 Partition X § 19 Exception Handling - // HandlerBlock ::= `handler` Label to Label - // Handler range is from first label ***prior to*** second (emphasis @jonpryor) - // Therefore we need to append `NOP` to the IL stream so that the fixupTarget is - // one-past-the-end, as nothing afterward has yet been emitted. - - il.Emit (OpCodes.Nop); - var fixupTarget = il.Body.Instructions.Last (); - - for (int i = 0; i < (body.ExceptionHandlers.Count-1); ++i) { - var c = body.ExceptionHandlers [i]; - var n = body.ExceptionHandlers [i+1]; - c.TryEnd = c.FilterStart ?? c.HandlerStart; - c.HandlerEnd = n.FilterStart ?? n.HandlerStart; - } - if (body.ExceptionHandlers.Count > 0) { - var f = body.ExceptionHandlers [body.ExceptionHandlers.Count-1]; - f.TryEnd = f.HandlerStart; - f.HandlerEnd = fixupTarget; - } - foreach (var fixup in FixupLeaveOffsets) { - fixup.Operand = fixupTarget; - } - } - finally { - TryStart = prevTryStart; - FixupLeaveOffsets = pFixupLeaveOffsets; - } - - return node; - } - - void EmitLeave () - { - // keep in sync w/ VisitGoto() - // Prevent multiple `leave OFFSET`s in the output - if (il.Body.Instructions.Last ().OpCode.Code != Code.Ret) { - il.Emit (OpCodes.Leave, il.Body.Instructions.Last ()); - FixupLeaveOffsets!.Add (il.Body.Instructions.Last ()); - } - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitTypeBinary ( - TypeBinaryExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitTypeBinary: {node}"); - return base.VisitTypeBinary (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitUnary ( - UnaryExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitUnary: {node}"); - return base.VisitUnary (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitMemberInit ( - MemberInitExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitMemberInit: {node}"); - return base.VisitMemberInit (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitListInit ( - ListInitExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitListInit: {node}"); - return base.VisitListInit (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override ElementInit VisitElementInit ( - ElementInit node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitElementInit: {node}"); - return base.VisitElementInit (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override MemberBinding VisitMemberBinding ( - MemberBinding node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitMemberBinding: {node}"); - return base.VisitMemberBinding (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override MemberAssignment VisitMemberAssignment ( - MemberAssignment node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitMemberAssignment: {node}"); - return base.VisitMemberAssignment (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override MemberMemberBinding VisitMemberMemberBinding ( - MemberMemberBinding node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitMemberMemberBinding: {node}"); - return base.VisitMemberMemberBinding (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override MemberListBinding VisitMemberListBinding ( - MemberListBinding node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitMemberListBinding: {node}"); - return base.VisitMemberListBinding (node); - } - - /// - /// Visits the children of the . - /// - /// The expression to visit. - /// The modified expression, if it or any subexpression was modified; - /// otherwise, returns the original expression. - protected override Expression VisitDynamic ( - DynamicExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: CecilCompilerExpressionVisitor.VisitDynamic: {node}"); - return base.VisitDynamic (node); - } -} diff --git a/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.cs b/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.cs deleted file mode 100644 index e66289184..000000000 --- a/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionAssemblyBuilder.cs +++ /dev/null @@ -1,443 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq.Expressions; -using System.Runtime.InteropServices; -using System.Text; - -using Java.Interop; -using Java.Interop.Tools.Diagnostics; - -using Mono.Cecil; -using Mono.Cecil.Cil; -using static System.Formats.Asn1.AsnWriter; - -namespace Java.Interop.Tools.Expressions; - -public class ExpressionAssemblyBuilder { - - public ExpressionAssemblyBuilder (AssemblyDefinition declaringAssemblyDefinition, Action? logger = null) - { - DeclaringAssemblyDefinition = declaringAssemblyDefinition; - Logger = logger ?? Diagnostic.CreateConsoleLogger (); - } - - public AssemblyDefinition DeclaringAssemblyDefinition {get;} - public Action Logger {get;} - public bool KeepTemporaryFiles {get; set;} - - public MethodDefinition Compile (LambdaExpression expression) - { - var mmDef = CreateMethodDefinition (DeclaringAssemblyDefinition, expression); - var decls = new VariableDefinitions (DeclaringAssemblyDefinition, mmDef, expression, Logger); - var mmBody = mmDef.Body; - var il = mmBody.GetILProcessor (); - var v = new CecilCompilerExpressionVisitor (DeclaringAssemblyDefinition, mmBody, decls, Logger); - v.Visit (expression); - - if (expression.ReturnType != null && expression.ReturnType != typeof (void) && decls.ReturnValue == null) { - Logger (TraceLevel.Error, $"# jonp: validation error: expression has a return type but we didn't find a return value! expression={expression}"); - } - - decls.ReturnValue?.Load (il); - il.Emit (OpCodes.Ret); - - return mmDef; - } - - static MethodDefinition CreateMethodDefinition (AssemblyDefinition declaringAssembly, LambdaExpression expression) - { - var mmDef = new MethodDefinition ( - name: "@CHANGE-ME@", - attributes: Mono.Cecil.MethodAttributes.Static | Mono.Cecil.MethodAttributes.Private | Mono.Cecil.MethodAttributes.HideBySig, - returnType: declaringAssembly.MainModule.ImportReference (expression.ReturnType) - ) { - Body = { - InitLocals = true, - }, - }; - return mmDef; - } - - public void AddRegistrationMethod (TypeDefinition declaringType, IList methods) - { - var registrations = new MethodDefinition ( - name: "__RegisterNativeMembers", - attributes: MethodAttributes.Static | MethodAttributes.Private | MethodAttributes.HideBySig, - returnType: DeclaringAssemblyDefinition.MainModule.TypeSystem.Void - ) { - Body = { - InitLocals = true, - }, - }; - - declaringType.Methods.Add (registrations); - - var ctor = typeof (JniAddNativeMethodRegistrationAttribute).GetConstructor (Type.EmptyTypes); - var attr = new CustomAttribute (DeclaringAssemblyDefinition.MainModule.ImportReference (ctor)); - registrations.CustomAttributes.Add (attr); - - var args = new ParameterDefinition ("args", default, DeclaringAssemblyDefinition.MainModule.ImportReference (typeof (JniNativeMethodRegistrationArguments))); - registrations.Parameters.Add (args); - - var arrayType = DeclaringAssemblyDefinition.MainModule.ImportReference (typeof (JniNativeMethodRegistration [])); - - var array = new VariableDefinition (arrayType); - registrations.Body.Variables.Add (array); - - var il = registrations.Body.GetILProcessor (); - EmitConsoleWriteLine (il, $"# jonp: called `{declaringType.FullName}.__RegisterNativeMembers()` w/ {methods.Count} methods to register."); - il.Emit (OpCodes.Ldc_I4, methods.Count); - il.Emit (OpCodes.Newarr, DeclaringAssemblyDefinition.MainModule.ImportReference (arrayType.GetElementType ())); - // il.Emit (OpCodes.Stloc_0); - - var JniNativeMethodRegistration_ctor = typeof (JniNativeMethodRegistration).GetConstructor (new [] { typeof (string), typeof (string), typeof (Delegate) }); - var jnmr_ctor = DeclaringAssemblyDefinition.MainModule.ImportReference (JniNativeMethodRegistration_ctor); - - for (int i = 0; i < methods.Count; i++) { - var delegateCtor = GetMarshalMethodDelegateCtor (methods [i].MarshalMethodDefinition); - - // il.Emit (OpCodes.Ldloc_0); // args - il.Emit (OpCodes.Dup); // args - il.Emit (OpCodes.Ldc_I4, i); // index of `args` to set - - // new JniNativeMethodRegistration (JniName, JniSignature, new _JniMarshal_PP… (MarshalMethodDefinition)) - il.Emit (OpCodes.Ldstr, methods [i].JniName); - il.Emit (OpCodes.Ldstr, methods [i].JniSignature); - il.Emit (OpCodes.Ldnull); - il.Emit (OpCodes.Ldftn, methods [i].MarshalMethodDefinition); - il.Emit (OpCodes.Newobj, delegateCtor); - il.Emit (OpCodes.Newobj, jnmr_ctor); - - il.Emit (OpCodes.Stelem_Any, arrayType.GetElementType ()); // args [i] = new JniNativeMethodRegistration (…) - } - - il.Emit (OpCodes.Stloc_0); - - Action> addRegistrations = new JniNativeMethodRegistrationArguments ().AddRegistrations; - il.Emit (OpCodes.Ldarga_S, args); - il.Emit (OpCodes.Ldloc_0); - il.Emit (OpCodes.Call, DeclaringAssemblyDefinition.MainModule.ImportReference (addRegistrations.Method)); - il.Emit (OpCodes.Ret); - } - - void EmitConsoleWriteLine (ILProcessor il, string message) - { - Action cwl = Console.WriteLine; - il.Emit (OpCodes.Ldstr, message); - il.Emit (OpCodes.Call, DeclaringAssemblyDefinition.MainModule.ImportReference (cwl.Method)); - } - - // Keep in sync w/ MarshalMemberBuilder.GetMarshalerType() - MethodReference GetMarshalMethodDelegateCtor (MethodDefinition method) - { - // Too many parameters; does a `_JniMarshal_*` type exist in the type's declaring assembly? - var delegateName = GetMarshalMethodDelegateName (method.Parameters, method.ReturnType); - - var delegateDef = DeclaringAssemblyDefinition.MainModule.GetType (delegateName.ToString ()); - if (delegateDef == null) { - delegateDef = CreateMarshalMethodDelegateType (delegateName, method.Parameters, method.ReturnType); - DeclaringAssemblyDefinition.MainModule.Types.Add (delegateDef); - } - return delegateDef.Methods.First (m => m.Name == ".ctor"); - } - - string GetMarshalMethodDelegateName (IList parameters, TypeReference returnType) - { - // Too many parameters; does a `_JniMarshal_*` type exist in the type's declaring assembly? - var delegateName = new StringBuilder (); - delegateName.Append ("_JniMarshal_PP"); - - for (int i = 2; i < parameters.Count; i++) { - delegateName.Append (GetJniMarshalDelegateParameterIdentifier (parameters [i].ParameterType)); - } - delegateName.Append ("_"); - delegateName.Append (GetJniMarshalDelegateParameterIdentifier (returnType)); - - return delegateName.ToString (); - } - - char GetJniMarshalDelegateParameterIdentifier (TypeReference type) - { - switch (type?.FullName) { - case "System.Boolean": return 'Z'; - case "System.Byte": return 'B'; - case "System.SByte": return 'B'; - case "System.Char": return 'C'; - case "System.Int16": return 'S'; - case "System.UInt16": return 's'; - case "System.Int32": return 'I'; - case "System.UInt32": return 'i'; - case "System.Int64": return 'J'; - case "System.UInt64": return 'j'; - case "System.Single": return 'F'; - case "System.Double": return 'D'; - case null: - case "System.Void": return 'V'; - default: return 'L'; - } - } - - public TypeDefinition CreateMarshalMethodDelegateType (string delegateName, IList parameters, TypeReference returnType) - { - var delegateDef = new TypeDefinition ( - @namespace: "", - name: delegateName, - attributes: TypeAttributes.Class | TypeAttributes.NotPublic | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass - ); - delegateDef.BaseType = DeclaringAssemblyDefinition.MainModule.ImportReference (typeof (MulticastDelegate)); - - var ufpCtor = typeof (UnmanagedFunctionPointerAttribute).GetConstructor (new[]{typeof (CallingConvention)}); - var ufpCtorRef = DeclaringAssemblyDefinition.MainModule.ImportReference (ufpCtor); - var ufpAttr = new CustomAttribute (ufpCtorRef); - ufpAttr.ConstructorArguments.Add ( - new CustomAttributeArgument ( - DeclaringAssemblyDefinition.MainModule.ImportReference (typeof (CallingConvention)), - CallingConvention.Winapi)); - delegateDef.CustomAttributes.Add (ufpAttr); - - var delegateCtor = new MethodDefinition ( - name: ".ctor", - attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, - returnType: DeclaringAssemblyDefinition.MainModule.TypeSystem.Void - ); - delegateCtor.ImplAttributes = MethodImplAttributes.Runtime | MethodImplAttributes.Managed; - delegateCtor.Parameters.Add (new ParameterDefinition ("object", default, DeclaringAssemblyDefinition.MainModule.TypeSystem.Object)); - delegateCtor.Parameters.Add (new ParameterDefinition ("method", default, DeclaringAssemblyDefinition.MainModule.TypeSystem.IntPtr)); - delegateDef.Methods.Add (delegateCtor); - - var invoke = new MethodDefinition ( - name: "Invoke", - attributes: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual, - returnType: returnType - ); - invoke.ImplAttributes = MethodImplAttributes.Runtime | MethodImplAttributes.Managed; - foreach (var p in parameters) { - invoke.Parameters.Add (new ParameterDefinition (p.Name, p.Attributes, p.ParameterType)); - } - delegateDef.Methods.Add (invoke); - - return delegateDef; - } - - - public void Write (string path) - { - Logger (TraceLevel.Verbose, $"# jonp: ExpressionAssemblyBuilder.Write to path={path}"); - var module = DeclaringAssemblyDefinition.MainModule; - - var c = new MemoryStream (); - DeclaringAssemblyDefinition.Write (c); - c.Position = 0; - - if (KeepTemporaryFiles) { - using var intermediate = File.Create (path + ".cecil"); - c.WriteTo (intermediate); - c.Position = 0; - } - - Logger (TraceLevel.Verbose, $"# jonp: ---"); - - var rp = new ReaderParameters { - InMemory = true, - ReadSymbols = false, - ReadWrite = false, - ReadingMode = ReadingMode.Immediate, - }; - var newAsm = AssemblyDefinition.ReadAssembly (c, rp); - module = newAsm.MainModule; - - var selfRef = module.AssemblyReferences.FirstOrDefault (r => r.Name == newAsm.Name.Name); - foreach (var member in module.GetMemberReferences ()) { - Logger (TraceLevel.Verbose, $"# jonp: looking at ref for member: [{member.DeclaringType.Scope?.Name}]{member}"); - if (member.DeclaringType.Scope == selfRef) { - Logger (TraceLevel.Verbose, $"# jonp: Fixing scope self ref for member: {member}"); - member.DeclaringType.Scope = null; - continue; - } - } - foreach (var type in module.GetTypeReferences ()) { - Logger (TraceLevel.Verbose, $"# jonp: looking at ref for type: [{type.Scope}]{type}"); - if (type.Scope == selfRef) { - Logger (TraceLevel.Verbose, $"# jonp: Fixing scope self ref for type: {type}"); - type.Scope = null; - continue; - } - } - if (selfRef != null) { - module.AssemblyReferences.Remove (selfRef); - } - newAsm.Write (path); - } - - static AssemblyNameReference GetSystemRuntimeReference () - { - var privateCorelibDir = Path.GetDirectoryName (typeof (object).Assembly.Location) ?? - throw new NotSupportedException ("Cannot find directory of `System.Private.CoreLib.dll`!"); - var systemRuntimePath = Path.Combine (privateCorelibDir, "System.Runtime.dll"); - if (!File.Exists (systemRuntimePath)) { - throw new NotSupportedException ($"Could not find `System.Runtime.dll`; looked at `{systemRuntimePath}`."); - } - var rp = new ReaderParameters { - InMemory = false, - ReadSymbols = false, - ReadWrite = false, - ReadingMode = ReadingMode.Deferred, - }; - using var systemRuntime = AssemblyDefinition.ReadAssembly (systemRuntimePath, rp); - var nameDef = systemRuntime.Name; - return new AssemblyNameReference (nameDef.Name, nameDef.Version) { - HashAlgorithm = nameDef.HashAlgorithm, - PublicKeyToken = nameDef.PublicKeyToken, - }; - } -} - -sealed class VariableInfo { - public VariableInfo (Action load, Action loadAddress, Action store) - { - Load = load; - LoadAddress = loadAddress; - Store = store; - } - - public readonly Action Load; - public readonly Action LoadAddress; - public readonly Action Store; -} - -sealed class VariableDefinitions { - - Dictionary variables = new (); - Action Logger; - - public VariableDefinitions (AssemblyDefinition declaringAssembly, MethodDefinition declaringMethod, LambdaExpression expression, Action logger) - { - Logger = logger; - for (int i = 0; i < expression.Parameters.Count; ++i) { - var c = expression.Parameters [i]; - var d = new ParameterDefinition (c.Name, default, declaringAssembly.MainModule.ImportReference (c.Type)); - declaringMethod.Parameters.Add (d); - - VariableInfo v; - - switch (i) { - case 0: - v = new VariableInfo (il => il.Emit (OpCodes.Ldarg_0), il => il.Emit (OpCodes.Ldarga, 0), il => il.Emit (OpCodes.Starg, 0)); - break; - case 1: - v = new VariableInfo (il => il.Emit (OpCodes.Ldarg_1), il => il.Emit (OpCodes.Ldarga, 1), il => il.Emit (OpCodes.Starg, 1)); - break; - case 2: - v = new VariableInfo (il => il.Emit (OpCodes.Ldarg_2), il => il.Emit (OpCodes.Ldarga, 2), il => il.Emit (OpCodes.Starg, 2)); - break; - case 3: - v = new VariableInfo (il => il.Emit (OpCodes.Ldarg_3), il => il.Emit (OpCodes.Ldarga, 3), il => il.Emit (OpCodes.Starg, 3)); - break; - default: - int x = i; - v = new VariableInfo (il => il.Emit (OpCodes.Ldarg, x), il => il.Emit (OpCodes.Ldarga, x), il => il.Emit (OpCodes.Starg, x)); - break; - } - variables [c] = v; - } - FillVariables (declaringAssembly, declaringMethod, expression); - } - - public VariableInfo? ReturnValue {get; private set;} - - public VariableInfo this [ParameterExpression e] { - get => variables [e]; - } - - void FillVariables ( - AssemblyDefinition declaringAssembly, - MethodDefinition declaringMethod, - Expression e) - { - var variableVisitor = new VariableExpressionVisitor (variables.Keys, Logger); - variableVisitor.Visit (e); - - Logger (TraceLevel.Verbose, $"# jonp: filling {variableVisitor.Variables.Count} variables"); - for (int i = 0; i < variableVisitor.Variables.Count; ++i) { - var c = variableVisitor.Variables [i]; - var d = new VariableDefinition (declaringAssembly.MainModule.ImportReference (c.Type)); - declaringMethod.Body.Variables.Add (d); - - VariableInfo v; - - switch (i) { - case 0: - v = new VariableInfo (il => il.Emit (OpCodes.Ldloc_0), il => il.Emit (OpCodes.Ldloca, 0), il => il.Emit (OpCodes.Stloc_0)); - break; - case 1: - v = new VariableInfo (il => il.Emit (OpCodes.Ldloc_1), il => il.Emit (OpCodes.Ldloca, 1), il => il.Emit (OpCodes.Stloc_1)); - break; - case 2: - v = new VariableInfo (il => il.Emit (OpCodes.Ldloc_2), il => il.Emit (OpCodes.Ldloca, 2), il => il.Emit (OpCodes.Stloc_2)); - break; - case 3: - v = new VariableInfo (il => il.Emit (OpCodes.Ldloc_3), il => il.Emit (OpCodes.Ldloca, 3), il => il.Emit (OpCodes.Stloc_3)); - break; - default: - var x = i; - v = new VariableInfo (il => il.Emit (OpCodes.Ldloc, x), il => il.Emit (OpCodes.Ldloca, x), il => il.Emit (OpCodes.Stloc, x)); - break; - } - variables [c] = v; - if (c == variableVisitor.ReturnValue) { - ReturnValue = v; - } - Logger (TraceLevel.Verbose, $"# jonp: FillVariables: local var {c.Name} is index {i}"); - } - } -} - -class VariableExpressionVisitor : ExpressionVisitor { - - public VariableExpressionVisitor (ICollection arguments, Action logger) - { - Arguments = arguments; - Logger = logger; - } - - ICollection Arguments; - Action Logger; - - public List Variables = new (); - public ParameterExpression? ReturnValue; - - protected override Expression VisitGoto ( - GotoExpression node) - { - Logger (TraceLevel.Verbose, $"# jonp: VariableExpressionVisitor.Goto: {node}; node.Kind={node.Kind}; node.Type={node.Type}"); - if (node.Kind != GotoExpressionKind.Return) { - return base.VisitGoto (node); - } - if (ReturnValue != null) { - return base.VisitGoto (node); - } - Logger (TraceLevel.Verbose, $"# jonp: VariableExpressionVisitor.Goto: node.Target={node.Target} node.Value={node.Value}"); - if (node.Value is ParameterExpression rv) { - ReturnValue = rv; - return base.VisitGoto (node); - } - if (node.Type == typeof (void)) { - return base.VisitGoto (node); - } - var p = Expression.Parameter (node.Type, "__goto.Return.Temporary"); - Variables.Add (p); - ReturnValue = p; - Logger (TraceLevel.Verbose, $"# jonp: VariableExpressionVisitor.Goto: setting ReturnValue={p}"); - return base.VisitGoto (node); - } - - protected override Expression VisitParameter ( - ParameterExpression node) - { - if (!Arguments.Contains (node) && !Variables.Contains (node)) { - Variables.Add (node); - } - return node; - } -} diff --git a/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.cs b/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.cs deleted file mode 100644 index 91ae63fe2..000000000 --- a/src/Java.Interop.Tools.Expressions/Java.Interop.Tools.Expressions/ExpressionMethodRegistration.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -using Mono.Cecil; - -namespace Java.Interop.Tools.Expressions; - -public record ExpressionMethodRegistration (string JniName, string JniSignature, MethodDefinition MarshalMethodDefinition) -{ -} diff --git a/src/Java.Interop/GlobalSuppressions.cs b/src/Java.Interop/GlobalSuppressions.cs index 6660520c6..64ae59b42 100644 --- a/src/Java.Interop/GlobalSuppressions.cs +++ b/src/Java.Interop/GlobalSuppressions.cs @@ -75,7 +75,6 @@ [assembly: SuppressMessage ("Performance", "CA1815:Override equals and operator equals on value types", Justification = "", Scope = "type", Target = "~T:Java.Interop.JniNativeMethodRegistrationArguments")] [assembly: SuppressMessage ("Performance", "CA1815:Override equals and operator equals on value types", Justification = "", Scope = "type", Target = "~T:Java.Interop.JniTransition")] -[assembly: SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:Java.Interop.JniRuntime.JniMarshalMemberBuilder.IsDirectMethod(System.Reflection.ParameterInfo[])~System.Boolean")] [assembly: SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~M:Java.Interop.JniRuntime.JniValueManager.GetJniIdentityHashCode(Java.Interop.JniObjectReference)~System.Int32")] [assembly: SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~P:Java.Interop.JniFieldInfo.Name")] [assembly: SuppressMessage ("Performance", "CA1822:Mark members as static", Justification = "", Scope = "member", Target = "~P:Java.Interop.JniFieldInfo.Signature")] diff --git a/src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.cs b/src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.cs index 2670e09f6..7d8de27cc 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.JniMarshalMemberBuilder.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; -using System.Runtime.CompilerServices; using System.Text; namespace Java.Interop { @@ -14,46 +13,18 @@ namespace Java.Interop { partial class JniRuntime { partial class CreationOptions { - public bool UseMarshalMemberBuilder {get; set;} = true; + [Obsolete ("JniMarshalMemberBuilder is no longer supported. This property will be removed in a future release.")] + public bool UseMarshalMemberBuilder {get; set;} + [Obsolete ("JniMarshalMemberBuilder is no longer supported. This property will be removed in a future release.")] public JniMarshalMemberBuilder? MarshalMemberBuilder {get; set;} } - JniMarshalMemberBuilder? marshalMemberBuilder; + [Obsolete ("JniMarshalMemberBuilder is no longer supported. This property will be removed in a future release.")] public JniMarshalMemberBuilder MarshalMemberBuilder { - get { - if (marshalMemberBuilder == null) - throw new NotSupportedException ("JniRuntime.ExportedMemberBuilder is not supported."); - return marshalMemberBuilder; - } - } - - internal bool UseMarshalMemberBuilder => marshalMemberBuilder != null; - - const string NotUsedInAndroid = "This code path is not used in Android projects."; - - // FIXME: https://github.com/dotnet/java-interop/issues/1192 - [DynamicDependency (DynamicallyAccessedMemberTypes.PublicParameterlessConstructor, "Java.Interop.MarshalMemberBuilder", "Java.Interop.Export")] - [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = NotUsedInAndroid)] - [UnconditionalSuppressMessage ("Trimming", "IL2035", Justification = "Java.Interop.Export.dll is not always present.")] - [UnconditionalSuppressMessage ("Trimming", "IL3050", Justification = NotUsedInAndroid)] - partial void SetMarshalMemberBuilder (CreationOptions options) - { - if (!options.UseMarshalMemberBuilder) { - return; - } - - if (options.MarshalMemberBuilder != null) { - marshalMemberBuilder = SetRuntime (options.MarshalMemberBuilder); - return; - } - - var t = Type.GetType ("Java.Interop.MarshalMemberBuilder, Java.Interop.Export", throwOnError: false); - if (t == null) - throw new InvalidOperationException ("Could not find Java.Interop.MarshalMemberBuilder from Java.Interop.Export.dll!"); - var b = (JniMarshalMemberBuilder) Activator.CreateInstance (t)!; - marshalMemberBuilder = SetRuntime (b); + get => throw new NotSupportedException ("JniMarshalMemberBuilder is no longer supported."); } + [Obsolete ("JniMarshalMemberBuilder is no longer supported. This class will be removed in a future release.")] public abstract class JniMarshalMemberBuilder : IDisposable, ISetRuntime { JniRuntime? runtime; @@ -87,9 +58,7 @@ protected virtual void Dispose (bool disposing) public Delegate CreateMarshalToManagedDelegate (Delegate value) { - if (value == null) - throw new ArgumentNullException (nameof (value)); - return CreateMarshalToManagedExpression (value.GetMethodInfo ()!).Compile (); + throw new NotSupportedException ("JniMarshalMemberBuilder is no longer supported."); } public abstract LambdaExpression CreateMarshalToManagedExpression (MethodInfo method); @@ -99,67 +68,17 @@ public Delegate CreateMarshalToM public Func CreateConstructActivationPeerFunc (ConstructorInfo constructor) { - if (constructor == null) - throw new ArgumentNullException (nameof (constructor)); - - var e = CreateConstructActivationPeerExpression (constructor); - return e.Compile (); + throw new NotSupportedException ("JniMarshalMemberBuilder is no longer supported."); } public string GetJniMethodSignature (MethodBase member) { - if (disposed) - throw new ObjectDisposedException (GetType ().Name); - - if (member == null) - throw new ArgumentNullException (nameof (member)); - - var signature = new StringBuilder ().Append ("("); - var memberParameters = member.GetParameters (); - foreach (var p in IsDirectMethod (memberParameters) ? memberParameters.Skip (2) : memberParameters) { - signature.Append (GetTypeSignature (p)); - } - signature.Append (")"); - - var method = member as MethodInfo; - if (method != null) { - signature.Append (GetTypeSignature (method.ReturnParameter)); - } else { - signature.Append ("V"); - } - - return signature.ToString (); - } - - string GetTypeSignature (ParameterInfo p) - { - var info = Runtime.TypeManager.GetTypeSignature (p.ParameterType); - if (info.IsValid) - return info.QualifiedReference; - - var marshaler = GetParameterMarshaler (p); - info = Runtime.TypeManager.GetTypeSignature (marshaler.MarshalType); - if (info.IsValid) - return info.QualifiedReference; - - throw new NotSupportedException ("Don't know how to determine JNI signature for parameter type: " + p.ParameterType.FullName + "."); + throw new NotSupportedException ("JniMarshalMemberBuilder is no longer supported."); } public JniValueMarshaler GetParameterMarshaler (ParameterInfo parameter) { - if (parameter.ParameterType == typeof (IntPtr)) - return IntPtrValueMarshaler.Instance; - - JniValueMarshalerAttribute? attr; - try { - attr = parameter.GetCustomAttribute (); - } catch (System.IndexOutOfRangeException) { - attr = null; - } - if (attr != null) { - return (JniValueMarshaler) Activator.CreateInstance (attr.MarshalerType)!; - } - return Runtime.ValueManager.GetValueMarshaler (parameter.ParameterType); + throw new NotSupportedException ("JniMarshalMemberBuilder is no longer supported."); } // Heuristic: if first two parameters are IntPtr, this is a "direct" wrapper. @@ -171,78 +90,5 @@ public bool IsDirectMethod (ParameterInfo[] methodParameters) } } } - - sealed class IntPtrValueMarshaler : JniValueMarshaler { - internal static IntPtrValueMarshaler Instance = new IntPtrValueMarshaler (); - - [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] - public override Expression CreateParameterFromManagedExpression (Java.Interop.Expressions.JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) - { - return sourceValue; - } - - [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] - [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] - public override Expression CreateParameterToManagedExpression (Java.Interop.Expressions.JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type? targetType) - { - return sourceValue; - } - - [RequiresDynamicCode (ExpressionRequiresUnreferencedCode)] - [RequiresUnreferencedCode (ExpressionRequiresUnreferencedCode)] - public override Expression CreateReturnValueFromManagedExpression (Java.Interop.Expressions.JniValueMarshalerContext context, ParameterExpression sourceValue) - { - return sourceValue; - } - - - public override object? CreateValue ( - ref JniObjectReference reference, - JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] - Type? targetType) - { - throw new NotSupportedException (); - } - - public override IntPtr CreateGenericValue ( - ref JniObjectReference reference, - JniObjectReferenceOptions options, - [DynamicallyAccessedMembers (Constructors)] - Type? targetType) - { - throw new NotSupportedException (); - } - - public override JniValueMarshalerState CreateArgumentState (object? value, ParameterAttributes synchronize) - { - throw new NotSupportedException (); - } - - public override JniValueMarshalerState CreateGenericArgumentState ([MaybeNull]IntPtr value, ParameterAttributes synchronize) - { - throw new NotSupportedException (); - } - - public override JniValueMarshalerState CreateObjectReferenceArgumentState (object? value, ParameterAttributes synchronize) - { - throw new NotSupportedException (); - } - - public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState ([MaybeNull]IntPtr value, ParameterAttributes synchronize) - { - throw new NotSupportedException (); - } - - public override void DestroyArgumentState (object? value, ref JniValueMarshalerState state, ParameterAttributes synchronize) - { - throw new NotSupportedException (); - } - - public override void DestroyGenericArgumentState (IntPtr value, ref JniValueMarshalerState state, ParameterAttributes synchronize) - { - throw new NotSupportedException (); - } - } } diff --git a/src/Java.Interop/Java.Interop/JniRuntime.cs b/src/Java.Interop/Java.Interop/JniRuntime.cs index 4f53620e4..66e843433 100644 --- a/src/Java.Interop/Java.Interop/JniRuntime.cs +++ b/src/Java.Interop/Java.Interop/JniRuntime.cs @@ -182,7 +182,6 @@ protected JniRuntime (CreationOptions options) Invoker = CreateInvoker (InvocationPointer); SetValueManager (options); - SetMarshalMemberBuilder (options); ObjectReferenceManager = SetRuntime (options.ObjectReferenceManager ?? throw new NotSupportedException ($"Please set {nameof (CreationOptions)}.{nameof (options.ObjectReferenceManager)}!")); TypeManager = SetRuntime (options.TypeManager ?? new JniTypeManager ()); @@ -253,7 +252,6 @@ T SetRuntime (T value) } partial void SetValueManager (CreationOptions options); - partial void SetMarshalMemberBuilder (CreationOptions options); static unsafe JavaVMInterface CreateInvoker (IntPtr handle) { @@ -315,7 +313,6 @@ protected virtual void Dispose (bool disposing) ClearTrackedReferences (); ValueManager.Dispose (); - marshalMemberBuilder?.Dispose (); TypeManager.Dispose (); ObjectReferenceManager.Dispose (); diff --git a/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs b/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs index d9f8e45bf..7dc315d52 100644 --- a/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs +++ b/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs @@ -2,20 +2,13 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.InteropServices; -using System.Threading; namespace Java.Interop { - using JniMethodMap = Dictionary<(string Name, string Signature), MethodInfo>; - public class JreTypeManager : JniRuntime.JniTypeManager { IDictionary? typeMappings; @@ -56,8 +49,6 @@ IEnumerable CreateSimpleReferencesEnumerator (Type type) } } - const string NotUsedInAndroid = "This code path is not used in Android projects."; - public override void RegisterNativeMembers ( JniType nativeClass, [DynamicallyAccessedMembers (MethodsAndPrivateNested)] @@ -68,101 +59,9 @@ public override void RegisterNativeMembers ( return; } - if (!Runtime.UseMarshalMemberBuilder) { - throw new NotSupportedException ("JniRuntime.MarshalMemberBuilder is required and not present."); - } - - var toRegister = new JniMethodMap (); - - AddInterfaceMethods (toRegister, type); - AddClassMethods (toRegister, type); - - // ignore methods… - - var builder = Runtime.MarshalMemberBuilder; - var registrations = new List(toRegister.Count); - - while (!methods.IsEmpty) { - int newLineIndex = methods.IndexOf ('\n'); - if (newLineIndex < 0) { - break; - } - var line = methods.Slice (0, newLineIndex); - methods = methods.Slice (newLineIndex+1); - GetNameAndSignature (line, out var name, out var signature); - - if (!toRegister.TryGetValue ((name, signature), out var method)) { - continue; - } - var marshaler = builder.CreateMarshalToManagedExpression (method).Compile (); - if (marshaler == null) { - throw new NotSupportedException ($"Could not create JNI marshal method for {method!.DeclaringType?.FullName}.{method!.Name}({signature})"); - } - registrations.Add (new JniNativeMethodRegistration (name, signature, marshaler!)); - } - - foreach (var registration in Runtime.MarshalMemberBuilder.GetExportedMemberRegistrations (type)) { - registrations.Add (registration); - } - - nativeClass.RegisterNativeMethods (registrations.ToArray ()); - } - - // FIXME: https://github.com/dotnet/java-interop/issues/1192 - [UnconditionalSuppressMessage ("Trimming", "IL2062", Justification = NotUsedInAndroid)] - [UnconditionalSuppressMessage ("Trimming", "IL2070", Justification = NotUsedInAndroid)] - [UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = NotUsedInAndroid)] - [UnconditionalSuppressMessage ("Trimming", "IL2078", Justification = NotUsedInAndroid)] - static void AddInterfaceMethods (JniMethodMap toRegister, Type type) - { - foreach (var iface in type.GetInterfaces ()) { - var ifaceSignature = iface.GetCustomAttribute (); - if (ifaceSignature == null || string.IsNullOrEmpty (ifaceSignature.SimpleReference)) { - continue; - } - var map = type.GetInterfaceMap (iface); - for (int i = 0; i < map.InterfaceMethods.Length; ++i) { - AddJniMethod (toRegister, map.InterfaceMethods [i], map.TargetMethods [i]); - } - } - } - - static void AddJniMethod (JniMethodMap toRegister, MethodInfo declaringMethod, MethodInfo? targetMethod = null) - { - var signature = declaringMethod.GetCustomAttribute(inherit: true); - if (signature == null || string.IsNullOrEmpty (signature.MemberName)) { - return; - } - toRegister [("n_" + signature.MemberName, signature.MemberSignature)] = targetMethod ?? declaringMethod; - } - - // FIXME: https://github.com/dotnet/java-interop/issues/1192 - [UnconditionalSuppressMessage ("Trimming", "IL2070", Justification = NotUsedInAndroid)] - static void AddClassMethods (JniMethodMap toRegister, [DynamicallyAccessedMembers (Methods)] Type type) - { - const BindingFlags Flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - foreach (var method in type.GetMethods (Flags)) { - AddJniMethod (toRegister, method); - } - foreach (var property in type.GetProperties (Flags)) { - var get = property.GetGetMethod (); - if (get != null) { - AddJniMethod (toRegister, get); - } - var set = property.GetSetMethod (); - if (set != null) { - AddJniMethod (toRegister, set); - } - } - } - - static void GetNameAndSignature (ReadOnlySpan line, out string name, out string signature) - { - int colon = line.IndexOf (':'); - name = new string (line.Slice (0, colon)); - line = line.Slice (colon+1); - colon = line.IndexOf (':'); - signature = new string (line.Slice (0, colon)); + throw new NotSupportedException ( + $"Could not register native members for type '{type.FullName}'. " + + "Ensure that the type has the appropriate [JniAddNativeMethodRegistration] attribute and static registration method."); } } } diff --git a/src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.cs b/src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.cs index aff5d4432..4c4cf4d37 100644 --- a/src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.cs +++ b/src/Java.Runtime.Environment/Java.Interop/ManagedValueManager.cs @@ -203,10 +203,6 @@ public override void ActivatePeer (IJavaPeerable? self, JniObjectReference refer var runtime = JniEnvironment.Runtime; try { - if (runtime.UseMarshalMemberBuilder) { - ActivateViaMarshalMemberBuilder (runtime.MarshalMemberBuilder, reference, cinfo, argumentValues); - return; - } ActivateViaReflection (reference, cinfo, argumentValues); } catch (Exception e) { var m = string.Format ("Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.", @@ -220,12 +216,6 @@ public override void ActivatePeer (IJavaPeerable? self, JniObjectReference refer } } - void ActivateViaMarshalMemberBuilder (JniRuntime.JniMarshalMemberBuilder builder, JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues) - { - var f = builder.CreateConstructActivationPeerFunc (cinfo); - f (cinfo, reference, argumentValues); - } - void ActivateViaReflection (JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues) { var declType = cinfo.DeclaringType ?? throw new NotSupportedException ("Do not know the type to create!"); diff --git a/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs b/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs index 4cae1dc48..0fcf1fa79 100644 --- a/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs +++ b/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs @@ -262,8 +262,10 @@ public override void ActivatePeer (IJavaPeerable? self, JniObjectReference refer var runtime = JniEnvironment.Runtime; try { - var f = runtime.MarshalMemberBuilder.CreateConstructActivationPeerFunc (cinfo); - f (cinfo, reference, argumentValues); + var declType = cinfo.DeclaringType ?? throw new NotSupportedException ("Do not know the type to create!"); + var instance = (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (declType); + instance.SetPeerReference (reference); + cinfo.Invoke (instance, argumentValues); } catch (Exception e) { var m = string.Format ("Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.", reference, diff --git a/src/Java.Runtime.Environment/Java.Runtime.Environment.csproj b/src/Java.Runtime.Environment/Java.Runtime.Environment.csproj index e027aa3d4..47a1c7ca6 100644 --- a/src/Java.Runtime.Environment/Java.Runtime.Environment.csproj +++ b/src/Java.Runtime.Environment/Java.Runtime.Environment.csproj @@ -18,7 +18,6 @@ - diff --git a/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs b/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs index 865074ef6..8d34c6c21 100644 --- a/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs +++ b/tests/Java.Interop-Tests/Java.Interop/JniRuntimeTest.cs @@ -113,31 +113,12 @@ static JniRuntime.CreationOptions CreateOptions (JniRuntime proxy) return new JniRuntime.CreationOptions { DestroyRuntimeOnDispose = false, InvocationPointer = proxy.InvocationPointer, - MarshalMemberBuilder = new ProxyMarshalMemberBuilder (), ObjectReferenceManager = new ProxyObjectReferenceManager (), ValueManager = new ProxyValueManager (), TypeManager = new ProxyTypeManager (), }; } - class ProxyMarshalMemberBuilder : JniMarshalMemberBuilder { - - public override System.Linq.Expressions.LambdaExpression CreateMarshalToManagedExpression (System.Reflection.MethodInfo method) - { - throw new NotImplementedException (); - } - - public override System.Collections.Generic.IEnumerable GetExportedMemberRegistrations (Type declaringType) - { - throw new NotImplementedException (); - } - - public override System.Linq.Expressions.Expression> CreateConstructActivationPeerExpression (System.Reflection.ConstructorInfo constructor) - { - throw new NotImplementedException (); - } - } - class ProxyObjectReferenceManager : JniObjectReferenceManager { public override int GlobalReferenceCount { diff --git a/tests/Java.Interop-Tests/Java.Interop/TestType.cs b/tests/Java.Interop-Tests/Java.Interop/TestType.cs index bd8804dd5..142da6470 100644 --- a/tests/Java.Interop-Tests/Java.Interop/TestType.cs +++ b/tests/Java.Interop-Tests/Java.Interop/TestType.cs @@ -110,7 +110,7 @@ public bool PropogateFinallyBlockExecuted { static Delegate GetEqualsThisHandler () { EqualsThisMarshalMethod h = _EqualsThis; - return JniEnvironment.Runtime.MarshalMemberBuilder.CreateMarshalToManagedDelegate (h); + return h; } delegate bool EqualsThisMarshalMethod (IntPtr jnienv, IntPtr n_self, IntPtr n_value); @@ -133,7 +133,7 @@ static bool _EqualsThis (IntPtr jnienv, IntPtr n_self, IntPtr n_value) static Delegate GetInt32ValueHandler () { GetInt32ValueMarshalMethod h = _GetInt32Value; - return JniEnvironment.Runtime.MarshalMemberBuilder.CreateMarshalToManagedDelegate (h); + return h; } delegate int GetInt32ValueMarshalMethod (IntPtr jnienv, IntPtr n_self); @@ -151,7 +151,7 @@ static int _GetInt32Value (IntPtr jnienv, IntPtr n_self) static Delegate _GetStringValueHandler () { GetStringValueMarshalMethod h = GetStringValueHandler; - return JniEnvironment.Runtime.MarshalMemberBuilder.CreateMarshalToManagedDelegate (h); + return h; } delegate IntPtr GetStringValueMarshalMethod (IntPtr jnienv, IntPtr n_self, int value); @@ -175,7 +175,7 @@ static IntPtr GetStringValueHandler (IntPtr jnienv, IntPtr n_self, int value) static Delegate GetMethodThrowsHandler () { MethodThrowsMarshalMethod h = MethodThrowsHandler; - return JniEnvironment.Runtime.MarshalMemberBuilder.CreateMarshalToManagedDelegate (h); + return h; } delegate void MethodThrowsMarshalMethod (IntPtr jnienv, IntPtr n_self); diff --git a/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csproj b/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csproj deleted file mode 100644 index b198a6511..000000000 --- a/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.csproj +++ /dev/null @@ -1,41 +0,0 @@ - - - - $(DotNetTargetFramework) - false - true - - - - - - $(TestOutputFullPath) - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targets b/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targets deleted file mode 100644 index b5eae7d58..000000000 --- a/tests/Java.Interop.Export-Tests/Java.Interop.Export-Tests.targets +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - <_RefAsmDirs Include="@(ReferencePathWithRefAssemblies->'%(RootDir)%(Directory).'->Distinct())" /> - - - <_JcwGen>"$(UtilityOutputFullPath)/jcw-gen.dll" - <_Target>--codegen-target JavaInterop1 - <_Output>-o "$(IntermediateOutputPath)/java" - <_Libpath>@(_RefAsmDirs->'-L "%(Identity)"', ' ') - - - - - - - - - <_JcwSource Include="$(IntermediateOutputPath)java\**\*.java" /> - - - <_Source Include="@(_JcwSource->Replace('%5c', '/'))" /> - <_Source Include="@(JavaExportTestJar->Replace('%5c', '/'))" /> - - - - <_JavacOpt Include="$(_JavacSourceOptions)" /> - <_JavacOpt Include="-d "$(IntermediateOutputPath)et-classes" " /> - <_JavacOpt Include="-classpath "$(OutputPath)java-interop.jar" " /> - <_JavacOpt Include=""@$(IntermediateOutputPath)_java_sources.txt"" /> - <_JavacOpt Include="-h "$(IntermediateOutputPath)et-classes" " /> - - - - - - - diff --git a/tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.cs b/tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.cs deleted file mode 100644 index aa89cb403..000000000 --- a/tests/Java.Interop.Export-Tests/Java.Interop/ExportTest.cs +++ /dev/null @@ -1,286 +0,0 @@ -using System; -using System.Linq.Expressions; -using System.Reflection; -using System.Collections.Generic; - -using Java.Interop; -using Java.Interop.Expressions; - -// For use by `jnimarshalmethod-gen.exe` & `make run-test-jnimarshal` -delegate bool _JniMarshal_PPZBCSIJFDLLLLLDFJ_Z ( - IntPtr jnienv, - IntPtr klass, - bool a, - sbyte b, - char c, - short d, - int e, - long f, - float g, - double h, - IntPtr i, // java.lang.Object - IntPtr j, // java.lang.String - IntPtr k, // java.util.ArrayList - IntPtr l, // java.lang.String - IntPtr m, // java.lang.Object - double n, - float o, - long p -); - -namespace Java.InteropTests -{ - [JniTypeSignature (JniTypeName, GenerateJavaPeer=false)] - public class ExportTest : JavaObject - { - internal const string JniTypeName = "net/dot/jni/test/ExportType"; - - [JniAddNativeMethodRegistrationAttribute] - static void RegisterNativeMembers (JniNativeMethodRegistrationArguments args) - { - args.AddRegistrations (JniEnvironment.Runtime.MarshalMemberBuilder.GetExportedMemberRegistrations (typeof (ExportTest))); - } - - public ExportTest (ref JniObjectReference reference, JniObjectReferenceOptions transfer) - : base (ref reference, transfer) - { - } - - public bool HelloCalled; - - [JavaCallable ("action", Signature="()V")] - public void InstanceAction () - { - HelloCalled = true; - } - - public static bool StaticHelloCalled; - - [JavaCallable ("staticAction", Signature="()V")] - public static void StaticAction () - { - StaticHelloCalled = true; - } - - public static bool StaticActionInt32StringCalled; - - [JavaCallable ("staticActionInt32String", Signature = "(ILjava/lang/String;)V")] - public static void StaticActionInt32String (int i, string v) - { - StaticActionInt32StringCalled = i == 1 && v == "2"; - } - - [JavaCallable ("staticFuncMyLegacyColorMyColor_MyColor")] - public static MyColor StaticFuncMyLegacyColorMyColor_MyColor ([JniValueMarshaler (typeof (MyLegacyColorValueMarshaler))] MyLegacyColor color1, MyColor color2) - { - return new MyColor (color1.Value + color2.Value); - } - - [JavaCallable ("funcInt64", Signature = "()J")] - public long FuncInt64 () - { - return 42; - } - - [JavaCallable ("funcIJavaObject", Signature = "()Ljava/lang/Object;")] - public JavaObject FuncIJavaObject () - { - return this; - } - - [JavaCallable ("actionIJavaObject", Signature="(Ljava/lang/Object;)V")] - public void InstanceActionIJavaObject (JavaObject test) - { - } - - [JavaCallable ("staticActionIJavaObject", Signature="(Ljava/lang/Object;)V")] - public static void StaticActionIJavaObject (JavaObject test) - { - } - - [JavaCallable ("staticActionInt", Signature="(I)V")] - public static void StaticActionInt (int i) - { - } - - [JavaCallable ("staticActionFloat", Signature="(F)V")] - public static void StaticActionFloat (float f) - { - } - - // TODO: [JavaCallable ("staticActionNullableFloat", Signature="(Ljava/lang/Float;)V")] - public static void StaticActionNullableFloat (float? f) - { - } - - [JavaCallable ("staticFuncThisMethodTakesLotsOfParameters", Signature="(ZBCSIJFDLjava/lang/Object;Ljava/lang/String;Ljava/util/ArrayList;Ljava/lang/String;Ljava/lang/Object;DFJ)Z")] - public static bool StaticFuncThisMethodTakesLotsOfParameters ( - bool a, - sbyte b, - char c, - short d, - int e, - long f, - float g, - double h, - IntPtr i, // java.lang.Object - IntPtr j, // java.lang.String - IntPtr k, // java.util.ArrayList - IntPtr l, // java.lang.String - IntPtr m, // java.lang.Object - double n, - float o, - long p) - { - if (a != false) - return false; - if (b != (byte) 0xb) - return false; - if (c != 'c') - return false; - if (d != (short) 0xd) - return false; - if (e != 0xe) - return false; - if (f != 0xf) - return false; - if (g != 1.0f) - return false; - if (h != 2.0) - return false; - if (i == IntPtr.Zero) - return false; - if (j == IntPtr.Zero) - return false; - if (k == IntPtr.Zero) - return false; - if (l == IntPtr.Zero) - return false; - if (m == IntPtr.Zero) - return false; - if (n != 3.0) - return false; - if (o != 4.0f) - return false; - if (p != 0x70) - return false; - return true; - } - } - - [JniValueMarshaler (typeof (MyColorValueMarshaler))] - public struct MyColor { - - public readonly int Value; - - public MyColor (int value) - { - Value = value; - } - } - - // Note: no [JniValueMarshaler] type; we use a parameter custom attribute instead. - public struct MyLegacyColor { - - public readonly int Value; - - public MyLegacyColor (int value) - { - Value = value; - } - } - - public interface MyInterface : IJavaPeerable - { - void MyMethod (); - } - - public class MyColorValueMarshaler : JniValueMarshaler { - - public override Type MarshalType { - get {return typeof (int);} - } - - public override MyColor CreateGenericValue (ref JniObjectReference reference, JniObjectReferenceOptions options, Type targetType) - { - throw new NotImplementedException (); - } - - public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState (MyColor value, ParameterAttributes synchronize) - { - throw new NotImplementedException (); - } - - public override void DestroyGenericArgumentState (MyColor value, ref JniValueMarshalerState state, ParameterAttributes synchronize) - { - throw new NotImplementedException (); - } - - public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type targetType) - { - var c = typeof (MyColor).GetConstructor (new[]{typeof (int)}); - var v = Expression.Variable (typeof (MyColor), sourceValue.Name + "_val"); - context.LocalVariables.Add (v); - context.CreationStatements.Add (Expression.Assign (v, Expression.New (c, sourceValue))); - return v; - } - - public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) - { - var r = Expression.Variable (MarshalType, sourceValue.Name + "_p"); - context.LocalVariables.Add (r); - context.CreationStatements.Add (Expression.Assign (r, Expression.Field (sourceValue, "Value"))); - return r; - } - - public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) - { - return CreateParameterFromManagedExpression (context, sourceValue, 0); - } - } - - public class MyLegacyColorValueMarshaler : JniValueMarshaler { - - public override Type MarshalType { - get {return typeof (int);} - } - - public override MyLegacyColor CreateGenericValue (ref JniObjectReference reference, JniObjectReferenceOptions options, Type targetType) - { - throw new NotImplementedException (); - } - - public override JniValueMarshalerState CreateGenericObjectReferenceArgumentState (MyLegacyColor value, ParameterAttributes synchronize) - { - throw new NotImplementedException (); - } - - public override void DestroyGenericArgumentState (MyLegacyColor value, ref JniValueMarshalerState state, ParameterAttributes synchronize) - { - throw new NotImplementedException (); - } - - public override Expression CreateParameterToManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize, Type targetType) - { - var c = typeof (MyLegacyColor).GetConstructor (new[]{typeof (int)}); - var v = Expression.Variable (typeof (MyLegacyColor), sourceValue.Name + "_val"); - context.LocalVariables.Add (v); - context.CreationStatements.Add (Expression.Assign (v, Expression.New (c, sourceValue))); - return v; - } - - public override Expression CreateParameterFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue, ParameterAttributes synchronize) - { - var r = Expression.Variable (MarshalType, sourceValue.Name + "_p"); - context.LocalVariables.Add (r); - context.CreationStatements.Add (Expression.Assign (r, Expression.Field (sourceValue, "Value"))); - return r; - } - - public override Expression CreateReturnValueFromManagedExpression (JniValueMarshalerContext context, ParameterExpression sourceValue) - { - return CreateParameterFromManagedExpression (context, sourceValue, 0); - } - } -} - diff --git a/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.cs b/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.cs deleted file mode 100644 index d3aeb7183..000000000 --- a/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExample.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System; -using System.Text; - -using Java.Interop; - -namespace Java.InteropTests; - -[JniTypeSignature (TypeSignature)] -class JavaCallableExample : Java.Lang.Object { - - internal const string TypeSignature = "net/dot/jni/test/JavaCallableExample"; - - [JavaCallableConstructor(SuperConstructorExpression="")] - public JavaCallableExample (int[] a, JavaInt32Array b) - { - this.a = a; - this.b = b; - - var bDescription = new StringBuilder (); - for (int i = 0; i < b.Length; ++i) { - if (i > 0) - bDescription.Append (", "); - bDescription.Append (b [i]); - } - Console.WriteLine ($"JavaCallableExample ({{{string.Join (", ", a)}}}, {{{bDescription}}})"); - } - - int[] a; - JavaInt32Array b; - - [JavaCallable ("getFirstA")] - public int GetFirstA () - { - return a [0]; - } -} diff --git a/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.cs b/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.cs deleted file mode 100644 index 99e3e5aa7..000000000 --- a/tests/Java.Interop.Export-Tests/Java.Interop/JavaCallableExampleTests.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Java.Interop; - -using NUnit.Framework; - -namespace Java.InteropTests; - -[TestFixture] -class JavaCallableExampleTest : JavaVMFixture -{ - [Test] - public void JavaCallableWrappers () - { - using var jce = CreateUseJavaCallableExampleType (); - var m = jce.GetStaticMethod ("test", "()Z"); - var z = JniEnvironment.StaticMethods.CallStaticBooleanMethod (jce.PeerReference, m); - Assert.IsTrue (z); - } - - [Test] - public void ManagedCtorInvokesJavaDefaultCtor () - { - using var o = new JavaCallableExample (new[]{1,2}, new JavaInt32Array (new[]{3,4})); - } - - static JniType CreateUseJavaCallableExampleType () => - new JniType ("net/dot/jni/test/UseJavaCallableExample"); -} diff --git a/tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.cs b/tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.cs deleted file mode 100644 index c22d6dae1..000000000 --- a/tests/Java.Interop.Export-Tests/Java.Interop/JavaVMFixture.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.IO; -using System.Diagnostics; -using System.Linq; - -using Java.Interop; - -namespace Java.InteropTests { - - public abstract partial class JavaVMFixture { - - static JavaVMFixture () - { - var c = new TestJVM ( - jars: new[]{ "export-test.jar" }, - typeMappings: new() { - [ExportTest.JniTypeName] = typeof (ExportTest), - [JavaCallableExample.TypeSignature] = typeof (JavaCallableExample), - } - ); - JniRuntime.SetCurrent (c); - } - - protected JavaVMFixture () - { - } - } -} - diff --git a/tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.cs b/tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.cs deleted file mode 100644 index 457d575bf..000000000 --- a/tests/Java.Interop.Export-Tests/Java.Interop/MarshalMemberBuilderTest.cs +++ /dev/null @@ -1,570 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; - -using Java.Interop; - -using Mono.Linq.Expressions; - -using NUnit.Framework; - -namespace Java.InteropTests -{ - [TestFixture] - class MarshalMemberBuilderTest : JavaVMFixture - { - [Test] - public void AddExportMethods () - { - using (var t = CreateExportTestType ()) { - var methods = CreateBuilder () - .GetExportedMemberRegistrations (typeof (ExportTest)) - .ToList (); - Assert.AreEqual (11, methods.Count); - - Assert.AreEqual ("n_InstanceAction", methods [0].Name); - Assert.AreEqual ("()V", methods [0].Signature); - - Assert.AreEqual ("n_StaticAction", methods [1].Name); - Assert.AreEqual ("()V", methods [1].Signature); - -#if NET - Assert.AreEqual ("_JniMarshal_PP_V", methods [0].Marshaler.GetType ().FullName); - Assert.AreEqual ("_JniMarshal_PP_V", methods [1].Marshaler.GetType ().FullName); -#else - Assert.IsTrue (methods [0].Marshaler is Action); - Assert.IsTrue (methods [1].Marshaler is Action); -#endif // NET - - var m = t.GetStaticMethod ("testStaticMethods", "()V"); - JniEnvironment.StaticMethods.CallStaticVoidMethod (t.PeerReference, m); - Assert.IsTrue (ExportTest.StaticHelloCalled); - Assert.IsTrue (ExportTest.StaticActionInt32StringCalled); - - using (var o = CreateExportTest (t)) { - var n = t.GetInstanceMethod ("testMethods", "()V"); - JniEnvironment.InstanceMethods.CallVoidMethod (o.PeerReference, n); - Assert.IsTrue (o.HelloCalled); - o.Dispose (); - } - } - } - - static MarshalMemberBuilder CreateBuilder () - { - return new MarshalMemberBuilder (JniRuntime.CurrentRuntime); - } - - static JniType CreateExportTestType () - { - return new JniType ("net/dot/jni/test/ExportType"); - } - - static unsafe ExportTest CreateExportTest (JniType type) - { - var c = type.GetConstructor ("()V"); - var p = type.NewObject (c, null); - return new ExportTest (ref p, JniObjectReferenceOptions.CopyAndDispose); - } - - [Test] - public void GetExportedMemberRegistrations_NullChecks () - { - var builder = CreateBuilder (); - Assert.Throws (() => builder.GetExportedMemberRegistrations (null)); - } - - [Test] - public void GetJniMethodSignature_NullChecks () - { - var builder = CreateBuilder (); - Action a = () => {}; - Assert.Throws (() => builder.GetJniMethodSignature (null, a.Method)); - Assert.Throws (() => builder.GetJniMethodSignature (new JavaCallableAttribute (), null)); - } - - [Test] - public void GetJniMethodSignature () - { - var builder = CreateBuilder (); - Action a = () => {}; - var export = new JavaCallableAttribute () { - Signature = "(I)V", - }; - // Note: no validation between actual MethodInfo & existing signature - // Validation would be done by CreateMarshalFromJniMethodRegistration(). - Assert.AreEqual ("(I)V", builder.GetJniMethodSignature (export, a.Method)); - Assert.AreEqual ("(I)V", export.Signature); - - export = new JavaCallableAttribute () { - Signature = null, - }; - Assert.AreEqual ("()V", builder.GetJniMethodSignature (export, a.Method)); - // Note: export.Signature updated - Assert.AreEqual ("()V", export.Signature); - - Action s = v => {}; - Assert.AreEqual ("(Ljava/lang/String;)V", builder.GetJniMethodSignature (new JavaCallableAttribute (), s.Method)); - - Action ds = (e, c, v) => {}; - Assert.AreEqual ("(Ljava/lang/String;)V", builder.GetJniMethodSignature (new JavaCallableAttribute (), ds.Method)); - - Func fs = () => null; - Assert.AreEqual ("()Ljava/lang/String;", builder.GetJniMethodSignature (new JavaCallableAttribute (), fs.Method)); - - Func dfs = (e, c) => null; - Assert.AreEqual ("()Ljava/lang/String;", builder.GetJniMethodSignature (new JavaCallableAttribute (), dfs.Method)); - - // Note: AppDomain currently has no builtin marshaling defaults - // TODO: but should it? We could default wrap to JavaProxyObject...? - Action aad = v => {}; - Assert.Throws (() => builder.GetJniMethodSignature (new JavaCallableAttribute (), aad.Method)); - - Func fad = () => null; - Assert.Throws (() => builder.GetJniMethodSignature (new JavaCallableAttribute (), fad.Method)); - } - - [Test] - public void CreateMarshalToManagedExpression_NullChecks () - { - Action a = ExportTest.StaticAction; - var builder = CreateBuilder (); - Assert.Throws (() => builder.CreateMarshalToManagedExpression (null)); - builder.CreateMarshalToManagedExpression (a.Method, null); - builder.CreateMarshalToManagedExpression (a.Method, null, null); - } - - [Test] - public void CreateMarshalToManagedExpression_SignatureMismatch () - { - Action a = ExportTest.StaticActionInt32String; - var builder = CreateBuilder (); - - // Parameter count mismatch: 0 != 2 - Assert.Throws(() => builder.CreateMarshalToManagedExpression ( - a.Method, new JavaCallableAttribute () { Signature = "()V" }, a.Method.DeclaringType)); - // Parameter count mismatch: 1 != 2 - Assert.Throws(() => builder.CreateMarshalToManagedExpression ( - a.Method, new JavaCallableAttribute () { Signature = "(I)V" }, a.Method.DeclaringType)); - // Parameter type mismatch: (int, int) != (int, string) - Assert.Throws(() => builder.CreateMarshalToManagedExpression ( - a.Method, new JavaCallableAttribute () { Signature = "(II)V" }, a.Method.DeclaringType)); - // return type mismatch: int != void - Assert.Throws(() => builder.CreateMarshalToManagedExpression ( - a.Method, new JavaCallableAttribute () { Signature = "(ILjava/lang/String;)I" }, a.Method.DeclaringType)); - // invalid JNI signatures - Assert.Throws(() => builder.CreateMarshalToManagedExpression ( - a.Method, new JavaCallableAttribute () { Signature = "(IL)I" }, a.Method.DeclaringType)); - Assert.Throws(() => builder.CreateMarshalToManagedExpression ( - a.Method, new JavaCallableAttribute () { Signature = "(I[)I" }, a.Method.DeclaringType)); - } - - [Test] - public void CreateMarshalFromJniMethodExpression_InstanceAction () - { - var t = typeof (ExportTest); - var m = t.GetMethod ("InstanceAction"); - CheckCreateMarshalToManagedExpression (null, t, m, typeof (Action), - @"void (IntPtr __jnienv, IntPtr __this) -{ - JniTransition __envp; - JniRuntime __jvm; - JniValueManager __vm; - ExportTest __this_val; - - __envp = new JniTransition(__jnienv); - try - { - __jvm = JniEnvironment.Runtime; - __vm = __jvm.ValueManager; - __vm.WaitForGCBridgeProcessing(); - __this_val = __vm.GetValue(__this); - __this_val.InstanceAction(); - } - catch (Exception __e) if (__jvm.ExceptionShouldTransitionToJni(__e)) - { - __envp.SetPendingException(__e); - } - finally - { - __envp.Dispose(); - } -}"); - } - - static void CheckCreateMarshalToManagedExpression (JavaCallableAttribute export, Type type, MethodInfo method, Type expectedDelegateType, string expectedBody) - { - export = export ?? new JavaCallableAttribute (); - var b = CreateBuilder (); - var l = b.CreateMarshalToManagedExpression (method, export, type); - CheckExpression (l, method.Name, expectedDelegateType, expectedBody); - } - - static void CheckExpression (LambdaExpression expression, string memberName, Type expressionType, string expectedBody) - { - Console.WriteLine ("## member: {0}", memberName); - Console.WriteLine (expression.ToCSharpCode ()); - Assert.AreEqual (expectedBody, expression.ToCSharpCode ()); -#if NET - // TODO: Use src/Java.Interop.Tools.Expressions to compile `expression` - // and use the "IL decompiler" in tests/Java.Interop.Tools.Expressions-Tests - // to verify the expected IL -#else - var da = AppDomain.CurrentDomain.DefineDynamicAssembly( - new AssemblyName("dyn"), // call it whatever you want - System.Reflection.Emit.AssemblyBuilderAccess.Save, - Path.GetDirectoryName (typeof (MarshalMemberBuilderTest).Assembly.Location)); - - var _name = "dyn-" + memberName + ".dll"; - var dm = da.DefineDynamicModule("dyn_mod", _name); - var dt = dm.DefineType ("dyn_type", TypeAttributes.Public); - var mb = dt.DefineMethod( - memberName, - MethodAttributes.Public | MethodAttributes.Static); - - expression.CompileToMethod (mb); - dt.CreateType(); - Assert.AreEqual (expressionType, expression.Type); -#if !__ANDROID__ - da.Save (_name); -#endif // !__ANDROID__ -#endif // !NET - } - - [Test] - public void CreateMarshalFromJniMethodExpression_StaticAction () - { - var t = typeof (ExportTest); - Action a = ExportTest.StaticAction; - CheckCreateMarshalToManagedExpression (null, t, a.Method, typeof(Action), - @"void (IntPtr __jnienv, IntPtr __class) -{ - JniTransition __envp; - JniRuntime __jvm; - - __envp = new JniTransition(__jnienv); - try - { - __jvm = JniEnvironment.Runtime; - __jvm.ValueManager.WaitForGCBridgeProcessing(); - ExportTest.StaticAction(); - } - catch (Exception __e) if (__jvm.ExceptionShouldTransitionToJni(__e)) - { - __envp.SetPendingException(__e); - } - finally - { - __envp.Dispose(); - } -}"); - } - - [Test] - public void CreateMarshalFromJniMethodExpression_StaticActionIJavaLangObject () - { - var t = typeof (ExportTest); - var m = t.GetMethod ("StaticActionIJavaObject"); - CheckCreateMarshalToManagedExpression (null, t, m, typeof(Action), - @"void (IntPtr __jnienv, IntPtr __class, IntPtr test) -{ - JniTransition __envp; - JniRuntime __jvm; - JniValueManager __vm; - JavaObject test_val; - - __envp = new JniTransition(__jnienv); - try - { - __jvm = JniEnvironment.Runtime; - __vm = __jvm.ValueManager; - __vm.WaitForGCBridgeProcessing(); - test_val = __vm.GetValue(test); - ExportTest.StaticActionIJavaObject(test_val); - } - catch (Exception __e) if (__jvm.ExceptionShouldTransitionToJni(__e)) - { - __envp.SetPendingException(__e); - } - finally - { - __envp.Dispose(); - } -}"); - } - - [Test] - public void CreateMarshalFromJniMethodExpression_InstanceActionIJavaLangObject () - { - var t = typeof (ExportTest); - var m = t.GetMethod ("InstanceActionIJavaObject"); - CheckCreateMarshalToManagedExpression (null, t, m, typeof(Action), - @"void (IntPtr __jnienv, IntPtr __this, IntPtr test) -{ - JniTransition __envp; - JniRuntime __jvm; - JniValueManager __vm; - ExportTest __this_val; - JavaObject test_val; - - __envp = new JniTransition(__jnienv); - try - { - __jvm = JniEnvironment.Runtime; - __vm = __jvm.ValueManager; - __vm.WaitForGCBridgeProcessing(); - __this_val = __vm.GetValue(__this); - test_val = __vm.GetValue(test); - __this_val.InstanceActionIJavaObject(test_val); - } - catch (Exception __e) if (__jvm.ExceptionShouldTransitionToJni(__e)) - { - __envp.SetPendingException(__e); - } - finally - { - __envp.Dispose(); - } -}"); - } - - [Test] - public void CreateMarshalFromJniMethodExpression_StaticActionInt32String () - { - var t = typeof (ExportTest); - var m = ((Action) ExportTest.StaticActionInt32String); - var e = new JavaCallableAttribute () { - Signature = "(ILjava/lang/String;)V", - }; - CheckCreateMarshalToManagedExpression (e, t, m.Method, typeof (Action), - @"void (IntPtr __jnienv, IntPtr __class, int i, IntPtr v) -{ - JniTransition __envp; - JniRuntime __jvm; - string v_val; - - __envp = new JniTransition(__jnienv); - try - { - __jvm = JniEnvironment.Runtime; - __jvm.ValueManager.WaitForGCBridgeProcessing(); - v_val = Strings.ToString(v); - ExportTest.StaticActionInt32String(i, v_val); - } - catch (Exception __e) if (__jvm.ExceptionShouldTransitionToJni(__e)) - { - __envp.SetPendingException(__e); - } - finally - { - __envp.Dispose(); - } -}"); - } - - [Test] - public void CreateMarshalFromJniMethodExpression_StaticFuncMyLegacyColorMyColor_MyColor () - { - var t = typeof (ExportTest); - var m = ((Func) ExportTest.StaticFuncMyLegacyColorMyColor_MyColor); - var e = new JavaCallableAttribute () { - Signature = "(II)I", - }; - CheckCreateMarshalToManagedExpression (e, t, m.Method, typeof (Func), - @"int (IntPtr __jnienv, IntPtr __class, int color1, int color2) -{ - JniTransition __envp; - JniRuntime __jvm; - MyColor __mret; - MyLegacyColor color1_val; - MyColor color2_val; - int __mret_p; - - __envp = new JniTransition(__jnienv); - try - { - __jvm = JniEnvironment.Runtime; - __jvm.ValueManager.WaitForGCBridgeProcessing(); - color1_val = new MyLegacyColor(color1); - color2_val = new MyColor(color2); - __mret = ExportTest.StaticFuncMyLegacyColorMyColor_MyColor(color1_val, color2_val); - __mret_p = __mret.Value; - return __mret_p; - } - catch (Exception __e) if (__jvm.ExceptionShouldTransitionToJni(__e)) - { - __envp.SetPendingException(__e); - return default(int); - } - finally - { - __envp.Dispose(); - } -}"); - } - - [Test] - public void CreateMarshalFromJniMethodExpression_FuncInt64 () - { - var t = typeof (ExportTest); - var m = t.GetMethod ("FuncInt64"); - var e = new JavaCallableAttribute () { - Signature = "()J", - }; - CheckCreateMarshalToManagedExpression (e, t, m, typeof (Func), - @"long (IntPtr __jnienv, IntPtr __this) -{ - JniTransition __envp; - JniRuntime __jvm; - JniValueManager __vm; - long __mret; - ExportTest __this_val; - - __envp = new JniTransition(__jnienv); - try - { - __jvm = JniEnvironment.Runtime; - __vm = __jvm.ValueManager; - __vm.WaitForGCBridgeProcessing(); - __this_val = __vm.GetValue(__this); - __mret = __this_val.FuncInt64(); - return __mret; - } - catch (Exception __e) if (__jvm.ExceptionShouldTransitionToJni(__e)) - { - __envp.SetPendingException(__e); - return default(long); - } - finally - { - __envp.Dispose(); - } -}"); - } - - [Test] - public void CreateMarshalFromJniMethodExpression_FuncIJavaObject () - { - var t = typeof (ExportTest); - var m = t.GetMethod ("FuncIJavaObject"); - var e = new JavaCallableAttribute () { - Signature = "()Ljava/lang/Object;", - }; - CheckCreateMarshalToManagedExpression (e, t, m, typeof (Func), - @"IntPtr (IntPtr __jnienv, IntPtr __this) -{ - JniTransition __envp; - JniRuntime __jvm; - JniValueManager __vm; - JavaObject __mret; - ExportTest __this_val; - JniObjectReference __mret_ref; - IntPtr __mret_rtn; - - __envp = new JniTransition(__jnienv); - try - { - __jvm = JniEnvironment.Runtime; - __vm = __jvm.ValueManager; - __vm.WaitForGCBridgeProcessing(); - __this_val = __vm.GetValue(__this); - __mret = __this_val.FuncIJavaObject(); - if (null == __mret) - { - return __mret_ref = new JniObjectReference(); - } - else - { - return __mret_ref = (IJavaPeerable)__mret.PeerReference; - } - __mret_rtn = References.NewReturnToJniRef(__mret_ref); - return __mret_rtn; - } - catch (Exception __e) if (__jvm.ExceptionShouldTransitionToJni(__e)) - { - __envp.SetPendingException(__e); - return default(IntPtr); - } - finally - { - __envp.Dispose(); - } -}"); - } - - static void DirectInvocation (IntPtr jnienv, IntPtr context) - { - } - - [Test] - public void CreateMarshalToManagedExpression_DirectMethod () - { - Action a = DirectInvocation; - var e = new JavaCallableAttribute () { - Signature = "()V", - }; - CheckCreateMarshalToManagedExpression (e, a.Method.DeclaringType, a.Method, typeof (Action), - @"void (IntPtr jnienv, IntPtr context) -{ - JniTransition __envp; - JniRuntime __jvm; - - __envp = new JniTransition(jnienv); - try - { - __jvm = JniEnvironment.Runtime; - __jvm.ValueManager.WaitForGCBridgeProcessing(); - MarshalMemberBuilderTest.DirectInvocation(jnienv, context); - } - catch (Exception __e) if (__jvm.ExceptionShouldTransitionToJni(__e)) - { - __envp.SetPendingException(__e); - } - finally - { - __envp.Dispose(); - } -}"); - } - - [Test] - public void CreateConstructActivationPeerExpression_Exceptions () - { - var b = CreateBuilder (); - Assert.Throws (() => b.CreateConstructActivationPeerExpression (null)); - } - - [Test] - public void CreateConstructActivationPeerExpression () - { - var b = CreateBuilder (); - var c = typeof (MarshalMemberBuilderTest).GetConstructor (new Type [0]); - var e = b.CreateConstructActivationPeerExpression (c); - - const string GetUninitializedObject_decltype = -#if NETCOREAPP - "RuntimeHelpers" -#else // !NETCOREAPP - "FormatterServices" -#endif // !NETCOREAPP - ; - - CheckExpression (e, - "ExportedMemberBuilderTest_ctor", - typeof(Func), - $@"object (ConstructorInfo constructor, JniObjectReference reference, object[] parameters) -{{ - Type type; - object self; - - type = constructor.DeclaringType; - self = {GetUninitializedObject_decltype}.GetUninitializedObject(type); - (IJavaPeerable)self.SetPeerReference(reference); - constructor.Invoke(self, parameters); - return self; -}}"); - } - } -} diff --git a/tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.java b/tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.java deleted file mode 100644 index a68d78d84..000000000 --- a/tests/Java.Interop.Export-Tests/java/net/dot/jni/test/ExportType.java +++ /dev/null @@ -1,162 +0,0 @@ -package net.dot.jni.test; - -import java.util.ArrayList; - -import net.dot.jni.GCUserPeerable; - -public class ExportType - implements GCUserPeerable -{ - - static { - net.dot.jni.ManagedPeer.registerNativeMembers ( - ExportType.class, - ""); - } - - public static void testStaticMethods () { - staticAction (); - staticActionInt32String (1, "2"); - - int v = staticFuncMyLegacyColorMyColor_MyColor (1, 41); - if (v != 42) - throw new Error ("staticFuncMyEnum_MyEnum should return 42!"); - } - - public static void staticAction () {n_StaticAction ();} - private static native void n_StaticAction (); - - public static void staticActionIJavaObject (Object test) {n_StaticActionIJavaObject(test);} - private static native void n_StaticActionIJavaObject (Object test); - - public static void staticActionInt32String (int i, String s) {n_StaticActionInt32String (i, s);} - private static native void n_StaticActionInt32String (int i, String s); - - public static int staticFuncMyLegacyColorMyColor_MyColor (int color1, int color2) {return n_StaticFuncMyLegacyColorMyColor_MyColor (color1, color2);} - private static native int n_StaticFuncMyLegacyColorMyColor_MyColor (int color1, int color2); - - public static boolean staticFuncThisMethodTakesLotsOfParameters ( - boolean a, - byte b, - char c, - short d, - int e, - long f, - float g, - double h, - Object i, - String j, - ArrayList k, - String l, - Object m, - double n, - float o, - long p) { - return n_StaticFuncThisMethodTakesLotsOfParameters ( - a, - b, - c, - d, - e, - f, - g, - h, - i, - j, - k, - l, - m, - n, - o, - p); - } - private static native boolean n_StaticFuncThisMethodTakesLotsOfParameters ( - boolean a, - byte b, - char c, - short d, - int e, - long f, - float g, - double h, - Object i, - String j, - ArrayList k, - String l, - Object m, - double n, - float o, - long p); - - public void testMethods () { - action (); - - actionIJavaObject (this); - - long j = funcInt64 (); - if (j != 42) - throw new Error ("funcInt64() should return 42!"); - - Object o = funcIJavaObject (); - if (o != this) - throw new Error ("funcIJavaObject() should return `this`!"); - - staticActionInt (1); - staticActionFloat (2.0f); - // staticActionNullableFloat (3.0f); - - boolean r = staticFuncThisMethodTakesLotsOfParameters ( - false, - (byte) 0xb, - 'c', - (short) 0xd, - 0xe, - 0xf, - 1.0f, - 2.0, - new Object (), - "j", - new ArrayList(), - "l", - new Object (), - 3.0, - 4.0f, - 0x70 - ); - if (r != true) - throw new Error ("staticFuncThisMethodTakesLotsOfParameters should return true!"); - } - - public void action () {n_InstanceAction ();} - private native void n_InstanceAction (); - - public void actionIJavaObject (Object test) {n_InstanceActionIJavaObject (test);} - private native void n_InstanceActionIJavaObject (Object test); - - public long funcInt64 () {return n_FuncInt64 ();} - private native long n_FuncInt64 (); - - public Object funcIJavaObject () {return n_FuncIJavaObject ();} - private native Object n_FuncIJavaObject (); - - public void staticActionInt (int i) {n_StaticActionInt (i);} - private native void n_StaticActionInt (int i); - - public void staticActionFloat (float f) {n_StaticActionFloat (f);} - private native void n_StaticActionFloat (float f); - - // public void staticActionNullableFloat (Float f) {n_StaticActionNullableFloat (f);} - // private native void n_StaticActionNullableFloat (Float f); - - ArrayList managedReferences = new ArrayList(); - - public void jiAddManagedReference (java.lang.Object obj) - { - managedReferences.add (obj); - } - - public void jiClearManagedReferences () - { - managedReferences.clear (); - } -} \ No newline at end of file diff --git a/tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.java b/tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.java deleted file mode 100644 index 24d603e78..000000000 --- a/tests/Java.Interop.Export-Tests/java/net/dot/jni/test/UseJavaCallableExample.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.dot.jni.test; - -import net.dot.jni.test.JavaCallableExample; - -public class UseJavaCallableExample { - - public static boolean test() { - JavaCallableExample e = new JavaCallableExample(new int[]{1,2}, new int[]{3, 4}); - return e.getFirstA() == 1; - } -} diff --git a/tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csproj b/tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csproj deleted file mode 100644 index daa5abff4..000000000 --- a/tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.Expressions-Tests.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - $(DotNetTargetFramework) - Java.Interop.Tools.ExpressionsTests - enable - enable - false - - - - - - $(TestOutputFullPath) - - - - - - - - - - - - - - - - - - - diff --git a/tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.cs b/tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.cs deleted file mode 100644 index 54e1f9998..000000000 --- a/tests/Java.Interop.Tools.Expressions-Tests/Java.Interop.Tools.ExpressionsTests/ExpressionAssemblyBuilderTests.cs +++ /dev/null @@ -1,444 +0,0 @@ -namespace Java.Interop.Tools.ExpressionsTests; - -using System.IO; -using System.Linq.Expressions; -using System.Text; - -using Java.Interop.Tools.Diagnostics; -using Java.Interop.Tools.Expressions; - -using Mono.Cecil; -using Mono.Cecil.Cil; - -using Mono.Linq.Expressions; - -[TestFixture] -public class ExpressionAssemblyBuilderTests -{ - static readonly string AssemblyModuleBaseName; - - static ExpressionAssemblyBuilderTests () - { - AssemblyModuleBaseName = typeof (ExpressionAssemblyBuilderTests).Assembly.GetName ().Name + - "-" + - nameof (ExpressionAssemblyBuilderTests); - } - - ExpressionAssemblyBuilder? ExpressionAssemblyBuilder; - AssemblyDefinition? AssemblyDefinition; - TypeDefinition? TypeDefinition; - - [OneTimeSetUp] - public void InitializeTestEnvironment () - { - var moduleParams = new ModuleParameters { - Kind = ModuleKind.Dll, - }; - AssemblyDefinition = AssemblyDefinition.CreateAssembly ( - assemblyName: new AssemblyNameDefinition (AssemblyModuleBaseName, new Version (0, 0, 0, 0)), - moduleName: AssemblyModuleBaseName + ".dll", - parameters: moduleParams - ); - TypeDefinition = new TypeDefinition ( - @namespace: "Example", - name: "Output", - attributes: TypeAttributes.Public | TypeAttributes.Sealed - ); - TypeDefinition.BaseType = AssemblyDefinition.MainModule.ImportReference (typeof (object)); - AssemblyDefinition.MainModule.Types.Add (TypeDefinition); - - ExpressionAssemblyBuilder = new ExpressionAssemblyBuilder (AssemblyDefinition) { - KeepTemporaryFiles = true, - }; - } - - [OneTimeTearDown] - public void TearDownTestEnvironment () - { - var path = Path.GetDirectoryName (typeof (ExpressionAssemblyBuilderTests).Assembly.Location) - ?? throw new InvalidOperationException ("`typeof (ExpressionAssemblyBuilderTests).Assembly.Location` is null?!"); - ExpressionAssemblyBuilder!.Write (Path.Combine (path, AssemblyModuleBaseName + ".dll")); - } - - void AddMethod (MethodDefinition method, [System.Runtime.CompilerServices.CallerMemberName] string methodName = "") - { - method.Name = methodName; - method.IsPublic = true; - TypeDefinition!.Methods.Add (method); - } - - [Test] - public void CreateMarshalMethodDelegateType () - { - var t = ExpressionAssemblyBuilder!.CreateMarshalMethodDelegateType ( - "_Jonp_Demo", - new [] { - new ParameterDefinition ("jnienv", default, AssemblyDefinition!.MainModule.TypeSystem.IntPtr), - new ParameterDefinition ("klass", default, AssemblyDefinition!.MainModule.TypeSystem.IntPtr), - new ParameterDefinition ("value", default, AssemblyDefinition!.MainModule.TypeSystem.Int32), - }, - AssemblyDefinition.MainModule.TypeSystem.IntPtr - ); - AssemblyDefinition.MainModule.Types.Add (t); - } - - [Test] - public void Compile_MethodCall () - { - Expression e = () => Console.WriteLine ("constant"); - var m = ExpressionAssemblyBuilder!.Compile (e); - - AddMethod (m); - - var expected = new[]{ - "Instruction_0000: ldstr \"constant\"", - "Instruction_0001: call System.Void System.Console::WriteLine(System.String)", - "Instruction_0002: ret", - }; - var actual = m.Body.Instructions; - Assert.AreEqual (expected.Length, actual.Count); - for (int i = 0; i < expected.Length; ++i) { - Assert.AreEqual (expected [i], GetDescription (actual, i)); - } - } - - [Test] - public void Compile_Condition_1 () - { - Expression> e = (a, b) => a == b; - var m = ExpressionAssemblyBuilder!.Compile (e); - - AddMethod (m); - - var expected = new[]{ - "Instruction_0000: ldarg.0", - "Instruction_0001: ldarg.1", - "Instruction_0002: ceq", - "Instruction_0003: ret", - }; - var actual = m.Body.Instructions; - Assert.AreEqual (expected.Length, actual.Count); - for (int i = 0; i < expected.Length; ++i) { - Assert.AreEqual (expected [i], GetDescription (actual, i)); - } - } - - [Test] - public void Compile_Condition_2 () - { - Expression> e = (a, b) => a == b ? 1 : 2; - var m = ExpressionAssemblyBuilder!.Compile (e); - - AddMethod (m); - - // Alas, branch targets d - var expected = new[]{ - "Instruction_0000: ldarg.0", - "Instruction_0001: ldarg.1", - "Instruction_0002: ceq", - "Instruction_0003: brfalse Instruction_0006", - "Instruction_0004: ldc.i4 1", - "Instruction_0005: br Instruction_0008", - "Instruction_0006: nop", - "Instruction_0007: ldc.i4 2", - "Instruction_0008: nop", - "Instruction_0009: ret", - }; - var actual = m.Body.Instructions; - Assert.AreEqual (expected.Length, actual.Count); - for (int i = 0; i < expected.Length; ++i) { - Assert.AreEqual (expected [i], GetDescription (actual, i)); - } - } - - [Test] - public void Compile_TryCatchFinally () - { - var exit = Expression.Label (typeof (int), "__exit"); - var tryBlock = Expression.Block (typeof (int), - E(() => Console.WriteLine ("try")).Body, - Expression.Return (target: exit, value: Expression.Constant (1), type: typeof (int)) - ); - var finallyBlock = E(() => Console.WriteLine ("finally")).Body; - var catchLog0 = E>(e => Console.WriteLine ("filtered")); - var catchFilt0 = Expression.Equal ( - Expression.Constant (null, typeof (Exception)), - Expression.Property (catchLog0.Parameters [0], "InnerException")); - var catchBlock0 = Expression.Block (typeof (int), - catchLog0.Body, - Expression.Return (target: exit, value: Expression.Constant (3), type: typeof (int)) - ); - var catchLog1 = E>(e => Console.WriteLine (e.ToString ())); - var catchBlock1 = Expression.Block (typeof (int), - catchLog1.Body, - Expression.Return (target: exit, value: Expression.Constant (4), type: typeof (int)) - ); - var block = new List { - Expression.TryCatchFinally ( - body: tryBlock, - @finally: finallyBlock, - handlers: new[]{ - Expression.Catch (catchLog0.Parameters[0], catchBlock0, catchFilt0), - Expression.Catch (catchLog1.Parameters[0], catchBlock1), - } - ), - Expression.Label (exit, Expression.Default (typeof (int))), - }; - var e = Expression.Lambda ( - delegateType: typeof (Func), - body: Expression.Block (variables: Array.Empty(), expressions: block), - name: nameof (Compile_TryCatchFinally), - tailCall: false, - parameters: Array.Empty() - ); - - Assert.AreEqual (1, ((Func) e.Compile ())()); - - var expectedCsharp = @"int Compile_TryCatchFinally() -{ - try - { - Console.WriteLine(""try""); - return 1; - } - catch (Exception e) if (null == e.InnerException) - { - Console.WriteLine(""filtered""); - return 3; - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - return 4; - } - finally - { - Console.WriteLine(""finally""); - } -}"; - Console.WriteLine ($"# jonp: expression tree as C#:"); - Console.WriteLine (e.ToCSharpCode ()); - Assert.AreEqual (expectedCsharp, e.ToCSharpCode ()); - - var m = ExpressionAssemblyBuilder!.Compile (e); - - AddMethod (m); - DumpInstructions (m); - - // Alas, branch targets d - var expected = new[]{ - // .try - "Instruction_0000: ldstr \"try\"", - "Instruction_0001: call System.Void System.Console::WriteLine(System.String)", - "Instruction_0002: ldc.i4 1", - "Instruction_0003: stloc.0", - "Instruction_0004: leave Instruction_0025", - // } - // filter { - "Instruction_0005: isinst System.Exception", - "Instruction_0006: dup", - "Instruction_0007: brtrue.s Instruction_000b", - "Instruction_0008: pop", - "Instruction_0009: ldc.i4.0", - "Instruction_000a: br.s Instruction_0012", - "Instruction_000b: stloc.1", - "Instruction_000c: ldnull", - "Instruction_000d: ldloc.1", - "Instruction_000e: callvirt System.Exception System.Exception::get_InnerException()", - "Instruction_000f: ceq", - "Instruction_0010: ldc.i4.0", - "Instruction_0011: cgt.un", - "Instruction_0012: endfilter", - // } - // { // handler - "Instruction_0013: castclass System.Exception", - "Instruction_0014: stloc.1", - "Instruction_0015: ldstr \"filtered\"", - "Instruction_0016: call System.Void System.Console::WriteLine(System.String)", - "Instruction_0017: ldc.i4 3", - "Instruction_0018: stloc.0", - "Instruction_0019: leave Instruction_0025", - // } - // catch class System.Exception { - "Instruction_001a: castclass System.Exception", - "Instruction_001b: stloc.2", - "Instruction_001c: ldloc.2", - "Instruction_001d: callvirt System.String System.Object::ToString()", - "Instruction_001e: call System.Void System.Console::WriteLine(System.String)", - "Instruction_001f: ldc.i4 4", - "Instruction_0020: stloc.0", - "Instruction_0021: leave Instruction_0025", - // } - // finally { - "Instruction_0022: ldstr \"finally\"", - "Instruction_0023: call System.Void System.Console::WriteLine(System.String)", - "Instruction_0024: endfinally", - // } - "Instruction_0025: nop", - "Instruction_0026: nop", - "Instruction_0027: ldloc.0", - "Instruction_0028: ret", - }; - var actual = m.Body.Instructions; - Assert.AreEqual (expected.Length, actual.Count); - for (int i = 0; i < expected.Length; ++i) { - Assert.AreEqual (expected [i], GetDescription (actual, i)); - } - } - - static Expression E(Expression e) - where TDelegate : Delegate - { - return e; - } - - - static void DumpInstructions (MethodDefinition method) - { - var body = method.Body; - var instructions = body.Instructions; - if (body.HasExceptionHandlers) { - foreach (var h in method.Body.ExceptionHandlers) { - Console.Error.WriteLine ($"// Handler: {h.HandlerType}"); - Console.Error.WriteLine( $"// \t" + - $" CatchType=`{h.CatchType}`"); - Console.Error.WriteLine ($"// \t" + - $" TryStart=`{GetDescription (body.Instructions, body.Instructions.IndexOf (h.TryStart))}` TryEnd=`{GetDescription (body.Instructions, body.Instructions.IndexOf (h.TryEnd))}`"); - Console.Error.WriteLine ($"// \t" + - $" FilterStart=`{GetDescription (body.Instructions, body.Instructions.IndexOf (h.FilterStart))}`"); - Console.Error.WriteLine ($"// \t" + - $" HandlerStart=`{GetDescription (body.Instructions, body.Instructions.IndexOf (h.HandlerStart))}` HandlerEnd=`{GetDescription (body.Instructions, body.Instructions.IndexOf (h.HandlerEnd))}`"); - Console.Error.WriteLine($""); - } - } - int indent = 0; - for (int i = 0; i < instructions.Count; ++i) { - var instruction = instructions [i]; - DumpStartHandler (ref indent, body, instructions, i); - Console.Error.WriteLine ("{0}{1,-40}\t; {2}", - new string (' ', indent*2), - GetDescription (instructions, i), - instructions[i].ToString ()); - DumpEndHandler (ref indent, body, instructions, i); - } - } - - static void DumpStartHandler (ref int indent, MethodBody body, Mono.Collections.Generic.Collection instructions, int i) - { - var instruction = instructions [i]; - if (!body.HasExceptionHandlers) { - return; - } - if (body.ExceptionHandlers.Any (e => e.TryStart == instruction)) { - Console.Error.WriteLine ($"{new string (' ', indent*2)}.try {{"); - indent++; - return; - } - var f = body.ExceptionHandlers.FirstOrDefault (e => e.FilterStart == instruction); - if (f != null) { - Console.Error.WriteLine ($"{new string(' ', indent*2)}filter {{"); - indent++; - return; - - } - var h = body.ExceptionHandlers.FirstOrDefault (e => e.HandlerStart == instruction); - if (h != null) { - switch (h.HandlerType) { - case ExceptionHandlerType.Finally: - Console.Error.WriteLine ($"{new string (' ', indent*2)}finally {{"); - break; - case ExceptionHandlerType.Catch: - Console.Error.WriteLine ($"{new string (' ', indent*2)}catch class {h.CatchType.FullName} {{"); - break; - case ExceptionHandlerType.Filter: - Console.Error.WriteLine ($"{new string(' ', indent * 2)}{{ // handler"); - break; - case ExceptionHandlerType.Fault: - default: - Console.Error.WriteLine ($"{new string (' ', indent*2)}{h.HandlerType} {{"); - break; - } - indent++; - return; - } - } - - static void DumpEndHandler (ref int indent, MethodBody body, Mono.Collections.Generic.Collection instructions, int i) - { - if (!body.HasExceptionHandlers) { - return; - } - if ((i + 1) >= instructions.Count) { - // End of instruction stream; clean up indentatino - if (indent == 0) - return; - indent--; - Console.Error.WriteLine ($"{new string (' ', indent)}}}"); - return; - } - // Handler range is from first label ***prior to*** second (emphasis @jonpryor) - // Thus, look at *next* instruction. - var instruction = instructions[i+1]; - if (body.ExceptionHandlers.Any (e => e.TryStart == instruction || e.FilterStart == instruction || e.HandlerStart == instruction || - e.TryEnd == instruction || e.HandlerEnd== instruction)) { - indent--; - Console.Error.WriteLine ($"{new string (' ', indent)}}}"); - } - } - - // Cribbed with changes from `Instruction.ToString()`: - // https://github.com/dotnet/cecil/blob/e069cd8d25d5b61b0e28fe65e75959c20af7aa80/Mono.Cecil.Cil/Instruction.cs#L95-L134 - // - // Don't want to use `Instruction.ToString()` as `Instruction.Offset` isn't updated until after - // `AssemblyDefinition.Write()`, and checking for `brfalse IL_0000` is not helpful. - static string GetDescription (IList instructions, int index) - { - if (index < 0) { - return ""; - } - var instruction = instructions [index]; - var description = new StringBuilder (); - - AppendLabel (index) - .Append (": ") - .Append (instruction.OpCode.Name); - - if (instruction.Operand == null) { - return description.ToString (); - } - - description.Append (" "); - - switch (instruction.OpCode.OperandType) { - case OperandType.ShortInlineBrTarget: - case OperandType.InlineBrTarget: - AppendLabel (instructions.IndexOf ((Instruction) instruction.Operand)); - break; - case OperandType.InlineSwitch: - var labels = (Instruction []) instruction.Operand; - for (int i = 0; i < labels.Length; i++) { - if (i > 0) - description.Append (','); - - AppendLabel (instructions.IndexOf (labels [i])); - } - break; - case OperandType.InlineString: - description.Append ('\"'); - description.Append (instruction.Operand); - description.Append ('\"'); - break; - default: - description.Append (instruction.Operand); - break; - } - - return description.ToString (); - - StringBuilder AppendLabel (int i) - { - return description.Append ("Instruction_") - .AppendFormat ("{0:x4}", i); - } - } -} diff --git a/tests/Java.Interop.Tools.Expressions-Tests/Usings.cs b/tests/Java.Interop.Tools.Expressions-Tests/Usings.cs deleted file mode 100644 index cefced496..000000000 --- a/tests/Java.Interop.Tools.Expressions-Tests/Usings.cs +++ /dev/null @@ -1 +0,0 @@ -global using NUnit.Framework; \ No newline at end of file diff --git a/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj b/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj index fc245d4d6..e19feea8f 100644 --- a/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj +++ b/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop.Tools.JavaCallableWrappers-Tests.csproj @@ -32,8 +32,6 @@ - - diff --git a/src/Java.Interop.Export/Java.Interop/JavaCallableAttribute.cs b/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.cs similarity index 100% rename from src/Java.Interop.Export/Java.Interop/JavaCallableAttribute.cs rename to tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableAttribute.cs diff --git a/src/Java.Interop.Export/Java.Interop/JavaCallableConstructorAttribute.cs b/tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.cs similarity index 100% rename from src/Java.Interop.Export/Java.Interop/JavaCallableConstructorAttribute.cs rename to tests/Java.Interop.Tools.JavaCallableWrappers-Tests/Java.Interop/JavaCallableConstructorAttribute.cs diff --git a/tools/jnimarshalmethod-gen/App.cs b/tools/jnimarshalmethod-gen/App.cs deleted file mode 100644 index 7479706e3..000000000 --- a/tools/jnimarshalmethod-gen/App.cs +++ /dev/null @@ -1,848 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Runtime.Loader; -using System.Text.RegularExpressions; -using System.Xml.Linq; - -using Java.Interop; - -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Options; -using Mono.Collections.Generic; -using Java.Interop.Tools.Cecil; -using Java.Interop.Tools.Expressions; - -#if _DUMP_REGISTER_NATIVE_MEMBERS -using Mono.Linq.Expressions; -#endif // _DUMP_REGISTER_NATIVE_MEMBERS - -namespace Xamarin.Android.Tools.JniMarshalMethodGenerator { - - class App : MarshalByRefObject - { - - internal const string Name = "jnimarshalmethod-gen"; - static DirectoryAssemblyResolver resolver; - static readonly TypeDefinitionCache cache = new TypeDefinitionCache (); - static Dictionary typeMap = new Dictionary (); - static List references = new List (); - static public bool Debug; - static public bool Verbose => Verbosity > 0; - static public int Verbosity; - static bool keepTemporary; - static bool forceRegeneration; - static List typeNameRegexes = new List (); - static string jvmDllPath; - List FilesToDelete = new List (); - // AssemblyLoadContext loadContext; - static string outDirectory; - - static readonly string AppName; - - static App() - { - AppName = Path.GetFileNameWithoutExtension (Environment.GetCommandLineArgs () [0]); - var r = new ReaderParameters { - ReadSymbols = true, - InMemory = true, - }; - resolver = new DirectoryAssemblyResolver ( - logger: Log, - loadDebugSymbols: true, - loadReaderParameters: r - ); - } - - public static int Main (string [] args) - { - var app = new App (); - app.AddMonoPathToResolverSearchDirectories (); - - var assemblies = app.ProcessArguments (args); - app.ProcessAssemblies (assemblies); - var filesToDelete = app.FilesToDelete; - - foreach (var path in filesToDelete) - File.Delete (path); - - return 0; - } - - static void Log (TraceLevel level, string message) - { - switch (level) { - case TraceLevel.Error: - ColorMessage ($"{AppName}: error: ", ConsoleColor.Red, Console.Error, writeLine: false); - ColorMessage (message, ConsoleColor.Red, Console.Error); - break; - case TraceLevel.Warning: - ColorMessage ($"{AppName}: warning: ", ConsoleColor.Yellow, Console.Error, writeLine: false); - ColorMessage (message, ConsoleColor.Yellow, Console.Error); - break; - case TraceLevel.Info: - if (Verbose) - ColorMessage (message, ConsoleColor.Cyan, Console.Out); - break; - case TraceLevel.Verbose: - if (Verbosity > 1) { - Console.WriteLine (message); - } - break; - default: - if (level == 0 || ((int) level) > Verbosity) { - Console.WriteLine (message); - } - break; - } - } - - void AddMonoPathToResolverSearchDirectories () - { - var monoPath = Environment.GetEnvironmentVariable ("MONO_PATH"); - if (string.IsNullOrWhiteSpace (monoPath)) - return; - - foreach (var path in monoPath.Split (new char [] { Path.PathSeparator })) { - resolver.SearchDirectories.Add (path); - - var facadesDirectory = Path.Combine (path, "Facades"); - if (Directory.Exists (facadesDirectory)) - resolver.SearchDirectories.Add (facadesDirectory); - } - } - - List ProcessArguments (string [] args) - { - var help = false; - var options = new OptionSet { - $"Usage: {Name}.exe OPTIONS* ASSEMBLY+ [@RESPONSE-FILES]", - "", - "Generates helper marshaling methods for specified assemblies.", - "", - "Copyright 2018 Microsoft Corporation", - "", - "Options:", - { "d|debug", - "Inject debug messages", - v => Debug = true }, - { "f", - "Force regeneration of marshal methods", - v => forceRegeneration = true }, - { "jvm=", - "{JVM} shared library path.", - v => jvmDllPath = v }, - { "keeptemp", - "Keep temporary *-JniMarshalMethod.dll files.", - v => keepTemporary = true }, - { "L=", - "{DIRECTORY} to resolve assemblies from.", - v => resolver.SearchDirectories.Add (v) }, - { "h|help|?", - "Show this message and exit", - v => help = v != null }, - { "o=", - "{DIRECTORY} to write updated assemblies", - v => outDirectory = v }, - { "r|reference=", - "Reference {ASSEMBLY} to use. Can be used multiple times.", - v => references.Add (v) - }, - { "types=", - "Generate marshaling methods only for types whose names match regex patterns listed {FILE}.\n" + - "One regex pattern per line.\n" + - "Empty lines and lines starting with '#' character are ignored as comments.", - v => LoadTypes (v) }, - { "t|type=", - "Generate marshaling methods only for types whose names match {TYPE-REGEX}.", - v => typeNameRegexes.Add (new Regex (v)) }, - { "v|verbose:", - "Output information about progress during the run of the tool", - (int? v) => Verbosity = v.HasValue ? v.Value : Verbosity + 1 }, - new ResponseFileSource(), - }; - - var assemblies = options.Parse (args); - if (help || args.Length < 1) { - options.WriteOptionDescriptions (Console.Out); - - Environment.Exit (0); - } - - if (assemblies.Count < 1) - ErrorAndExit (Message.ErrorAtLeastOneAssembly); - - return assemblies; - } - - void LoadTypes (string typesPath) - { - try { - foreach (var line in File.ReadLines (typesPath)) { - if (string.IsNullOrWhiteSpace (line)) - continue; - - if (line [0] == '#') - continue; - - typeNameRegexes.Add (new Regex (line)); - } - } catch (Exception e) { - ErrorAndExit (Message.ErrorUnableToReadProfile, typesPath, Environment.NewLine, e); - } - } - - void ProcessAssemblies (List assemblies) - { - CreateJavaVM (jvmDllPath); - - var readerParameters = new ReaderParameters { - AssemblyResolver = resolver, - InMemory = true, - ReadSymbols = true, - ReadWrite = false, - }; - var readerParametersNoSymbols = new ReaderParameters { - AssemblyResolver = resolver, - InMemory = true, - ReadSymbols = false, - ReadWrite = false, - }; - - foreach (var r in references) { - resolver.SearchDirectories.Add (Path.GetDirectoryName (r)); - } - foreach (var assembly in assemblies) { - resolver.SearchDirectories.Add (Path.GetDirectoryName (assembly)); - } - var corlibDir = Path.GetDirectoryName (typeof (object).Assembly.Location); - if (corlibDir != null) { - resolver.SearchDirectories.Add (corlibDir); - } - - // loadContext = CreateLoadContext (); - AppDomain.CurrentDomain.AssemblyResolve += (o, e) => { - Log (TraceLevel.Verbose, $"# jonp: resolving assembly: {e.Name}"); - var name = new AssemblyName (e.Name); - foreach (var d in resolver.SearchDirectories) { - var a = Path.Combine (d, name.Name); - var f = a + ".dll"; - if (File.Exists (f)) { - return Assembly.LoadFile (Path.GetFullPath (f)); - } - f = a + ".exe"; - if (File.Exists (f)) { - return Assembly.LoadFile (Path.GetFullPath (f)); - } - } - return null; - }; - - foreach (var r in references) { - try { - // loadContext.LoadFromAssemblyPath (Path.GetFullPath (r)); - Assembly.LoadFile (Path.GetFullPath (r)); - } catch (Exception e) { - Console.WriteLine (e); - ErrorAndExit (Message.ErrorUnableToPreloadReference, r); - } - } - - foreach (var assembly in assemblies) { - if (!File.Exists (assembly)) { - ErrorAndExit (Message.ErrorPathDoesNotExist, assembly); - } - bool inPlaceUpdate = string.IsNullOrEmpty (outDirectory) || - string.Equals (Path.GetFullPath (outDirectory), Path.GetDirectoryName (Path.GetFullPath (assembly)), StringComparison.OrdinalIgnoreCase); - - readerParameters.ReadWrite = readerParametersNoSymbols.ReadWrite = inPlaceUpdate; - - AssemblyDefinition ad; - try { - if (inPlaceUpdate) { - File.Copy (assembly, assembly + ".orig"); - } - ad = AssemblyDefinition.ReadAssembly (assembly, readerParameters); - resolver.AddToCache (ad); - } catch (Exception) { - if (Verbose) - Information ($"Unable to read assembly '{assembly}' with symbols. Retrying to load it without them."); - - ad = AssemblyDefinition.ReadAssembly (assembly, readerParametersNoSymbols); - resolver.AddToCache (ad); - } - - Extensions.MethodMap.Clear (); - } - - foreach (var assembly in assemblies) { - try { - CreateMarshalMethodAssembly (assembly); - } catch (Exception e) { - ErrorAndExit (Message.ErrorUnableToProcessAssembly, assembly, Environment.NewLine, e.Message, e); - } - } - } - - void CreateJavaVM (string jvmDllPath) - { - if (string.IsNullOrEmpty (jvmDllPath)) { - jvmDllPath = ReadJavaSdkDirectoryFromJdkInfoProps (); - } - var builder = new JreRuntimeOptions { - JvmLibraryPath = jvmDllPath, - }; - - try { - builder.CreateJreVM (); - } catch (Exception e) { - ErrorAndExit (Message.ErrorUnableToCreateJavaVM, Environment.NewLine, e); - } - } - - static string ReadJavaSdkDirectoryFromJdkInfoProps () - { - var location = typeof (App).Assembly.Location; // …/bin/Debug-net7.0/jnimarshalmethod-gen.dll - var binDir = Path.GetDirectoryName (Path.GetDirectoryName (location)) ?? Environment.CurrentDirectory; - var dirName = Path.GetFileName (Path.GetDirectoryName (location)); - if (binDir == null || dirName == null) { - return null; - } - if (!dirName.StartsWith ("Debug", StringComparison.OrdinalIgnoreCase) && - !dirName.StartsWith ("Release", StringComparison.OrdinalIgnoreCase)) { - return null; - } - var buildName = "Build" + dirName; - if (buildName.Contains ('-')) { - buildName = buildName.Substring (0, buildName.IndexOf ('-')); - } - var jdkPropFile = Path.Combine (binDir, buildName, "JdkInfo.props"); - if (!File.Exists (jdkPropFile)) { - return null; - } - - var msbuild = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003"); - - var jdkProps = XDocument.Load (jdkPropFile); - var jdkJvmPath = jdkProps.Elements () - .Elements (msbuild + "Choose") - .Elements (msbuild + "When") - .Elements (msbuild + "PropertyGroup") - .Elements (msbuild + "JdkJvmPath") - .FirstOrDefault (); - if (jdkJvmPath == null) { - return null; - } - return jdkJvmPath.Value; - } - - AssemblyLoadContext CreateLoadContext () - { - var c = new AssemblyLoadContext ("jnimarshalmethod-gen", isCollectible: true); - c.Resolving += (context, name) => { - Log (TraceLevel.Verbose, $"# jonp: trying to load assembly: {name}"); - if (name.Name == "Java.Interop") { - return typeof (IJavaPeerable).Assembly; - } - if (name.Name == "Java.Interop.Export") { - return typeof (JavaCallableAttribute).Assembly; - } - foreach (var d in resolver.SearchDirectories) { - var a = Path.Combine (d, name.Name); - var f = a + ".dll"; - if (File.Exists (f)) { - return context.LoadFromAssemblyPath (Path.GetFullPath (f)); - } - f = a + ".exe"; - if (File.Exists (f)) { - return context.LoadFromAssemblyPath (Path.GetFullPath (f)); - } - } - return null; - }; - return c; - } - - static JniRuntime.JniMarshalMemberBuilder CreateExportedMemberBuilder () - { - return JniEnvironment.Runtime.MarshalMemberBuilder; - } - - class MethodsComparer : IComparer - { - readonly Type type; - readonly TypeDefinition td; - - public MethodsComparer (Type type, TypeDefinition td) - { - this.type = type; - this.td = td; - } - - public int Compare (MethodInfo a, MethodInfo b) - { - if (a.DeclaringType != type) - return 1; - - var atd = td.GetMethodDefinition (a); - if (atd == null) - return 1; - - if (b.DeclaringType != type) - return -1; - - var btd = td.GetMethodDefinition (b); - if (btd == null) - return -1; - - if (atd.HasOverrides ^ btd.HasOverrides) - return btd.HasOverrides ? -1 : 1; - - return string.Compare (a.Name, b.Name, StringComparison.Ordinal); - } - } - - static HashSet addedMethods = new HashSet (); - - void CreateMarshalMethodAssembly (string path) - { - var baseName = Path.GetFileNameWithoutExtension (path); - var assemblyName = new AssemblyName (baseName + "-JniMarshalMethods"); - var fileName = assemblyName.Name + ".dll"; - var destDir = string.IsNullOrEmpty (outDirectory) ? Path.GetDirectoryName (path) : outDirectory; - var builder = CreateExportedMemberBuilder (); - var matchType = typeNameRegexes.Count > 0; - - if (Verbose) - ColorWriteLine ($"Preparing marshal method assembly '{assemblyName}'", ConsoleColor.Cyan); - - var ad = resolver.GetAssembly (path); - - var assemblyBuilder = new ExpressionAssemblyBuilder (ad, Log) { - KeepTemporaryFiles = keepTemporary, - }; - - PrepareTypeMap (ad.MainModule); - -// var assembly = loadContext.LoadFromStream (File.OpenRead (path)); - var assemblyBytes = File.ReadAllBytes (path); - var assembly = Assembly.Load (assemblyBytes); - - Type[] types = null; - try { - types = assembly.GetTypes (); - } catch (ReflectionTypeLoadException e) { - types = e.Types; - foreach (var le in e.LoaderExceptions) - Warning (Message.WarningTypeLoadException, Environment.NewLine, le); - if (Verbose) { - ColorMessage ($"Exception: {e.ToString ()}", ConsoleColor.Red, Console.Error); - } - } - - foreach (var systemType in types) { - if (systemType == null) - continue; - - var type = systemType.GetTypeInfo (); - - if (matchType) { - var matched = false; - - foreach (var r in typeNameRegexes) - matched |= r.IsMatch (type.FullName); - - if (!matched) - continue; - } - - if (type.IsInterface || type.IsGenericType || type.IsGenericTypeDefinition) - continue; - - var td = FindType (type); - - if (td == null) { - if (Verbose) - Warning (Message.WarningUnableToFindTypeDefinition, type); - - continue; - } - if (!td.ImplementsInterface ("Java.Interop.IJavaPeerable", cache)) - continue; - - var existingMarshalMethodsType = td.GetNestedType (TypeMover.NestedName); - if (existingMarshalMethodsType != null) { - - if (forceRegeneration) { - td.NestedTypes.Remove (existingMarshalMethodsType); - } else { - Warning (Message.WarningMarshalMethodsTypeAlreadyExists, existingMarshalMethodsType.GetAssemblyQualifiedName (cache), assemblyName); - return; - } - } - - if (Verbose) - ColorWriteLine ($"Processing {type} type", ConsoleColor.Yellow); - - var registrations = new List (); - var targetType = Expression.Variable (typeof(Type), "targetType"); - - var flags = BindingFlags.Public | BindingFlags.NonPublic | - BindingFlags.Instance | BindingFlags.Static; - - var methods = type.GetMethods (flags); - Array.Sort (methods, new MethodsComparer (type, td)); - - addedMethods.Clear (); - var mmTypeDef = new TypeDefinition ( - @namespace: null, - name: TypeMover.NestedName, - attributes: Mono.Cecil.TypeAttributes.NestedPrivate - ); - mmTypeDef.BaseType = assemblyBuilder.DeclaringAssemblyDefinition.MainModule.TypeSystem.Object; - - foreach (var method in methods) { - // TODO: Constructors - var export = method.GetCustomAttribute (); - var exportObj = method.GetCustomAttributes (inherit:false).SingleOrDefault (a => a.GetType ().Name == "JavaCallableAttribute"); - string signature = null; - string name = null; - string methodName = method.Name; - - if (exportObj != null) { - dynamic e = exportObj; - name = "n_" + methodName; - signature = e.Signature; - } - else { - if (method.IsGenericMethod || method.ContainsGenericParameters || method.IsGenericMethodDefinition || method.ReturnType.IsGenericType) - continue; - - if (method.DeclaringType != type) - continue; - - var md = td.GetMethodDefinition (method); - - if (md == null) { - if (Verbose) - Warning (Message.WarningUnableToFindMethodDefinition, method); - - continue; - } - - if (!md.NeedsMarshalMethod (resolver, cache, method, ref name, ref methodName, ref signature)) - continue; - } - - if (addedMethods.Contains (methodName)) { - Log (TraceLevel.Verbose, $"# jonp: method `{methodName}` already added (?!)"); - continue; - } - - if (Verbose) { - Console.Write ("Adding marshal method for "); - ColorWriteLine ($"{method}", ConsoleColor.Green ); - } - - var lambda = builder.CreateMarshalToManagedExpression (method); -#if _DUMP_REGISTER_NATIVE_MEMBERS - Log (TraceLevel.Verbose, $"## Dumping contents of marshal method for `{td.FullName}::{method.Name}({string.Join (", ", method.GetParameters ().Select (p => p.ParameterType))})`:"); - Console.WriteLine (lambda.ToCSharpCode ()); -#endif // _DUMP_REGISTER_NATIVE_MEMBERS - - var mmDef = assemblyBuilder.Compile (lambda); - mmDef.Name = name; - mmTypeDef.Methods.Add (mmDef); - - signature = export?.Signature ?? builder.GetJniMethodSignature (method); - - registrations.Add (new ExpressionMethodRegistration (name, signature, mmDef)); - - addedMethods.Add (methodName); - } - if (registrations.Count > 0) { - td.NestedTypes.Add (mmTypeDef); - assemblyBuilder.AddRegistrationMethod (mmTypeDef, registrations); - } - } - - if (Verbose) - ColorWriteLine ($"Marshal method assembly '{assemblyName}' created", ConsoleColor.Cyan); - - resolver.SearchDirectories.Add (destDir); - // var dstAssembly = resolver.GetAssembly (fileName); - - if (!string.IsNullOrEmpty (outDirectory)) { - Directory.CreateDirectory (outDirectory); - path = Path.Combine (outDirectory, Path.GetFileName (path)); - } - - assemblyBuilder.Write (path); - - // var mover = new TypeMover (dstAssembly, ad, path, definedTypes, resolver, cache); - // mover.Move (); - - // if (!keepTemporary) - // FilesToDelete.Add (dstAssembly.MainModule.FileName); - } - - static readonly MethodInfo Delegate_CreateDelegate = typeof (Delegate).GetMethod ("CreateDelegate", new[] { - typeof (Type), - typeof (Type), - typeof (string), - }); - static readonly ConstructorInfo JniNativeMethodRegistration_ctor = typeof (JniNativeMethodRegistration).GetConstructor (new[] { - typeof (string), - typeof (string), - typeof (Delegate), - }); - static readonly MethodInfo JniNativeMethodRegistrationArguments_AddRegistrations = typeof (JniNativeMethodRegistrationArguments).GetMethod ("AddRegistrations", new[] { - typeof (IEnumerable), - }); - static readonly MethodInfo Type_GetType = typeof (Type).GetMethod ("GetType", new[] { - typeof (string), - }); - - static Expression CreateRegistration (string method, string signature, LambdaExpression lambda, ParameterExpression targetType, string methodName) - { - Expression registrationDelegateType = null; - if (lambda.Type.Assembly == typeof (object).Assembly || - lambda.Type.Assembly == typeof (System.Linq.Enumerable).Assembly) { - registrationDelegateType = Expression.Constant (lambda.Type, typeof (Type)); - } - else { - Func getType = Type.GetType; - registrationDelegateType = Expression.Call (getType.GetMethodInfo (), - Expression.Constant (lambda.Type.FullName, typeof (string)), - Expression.Constant (true, typeof (bool))); - registrationDelegateType = Expression.Convert (registrationDelegateType, typeof (Type)); - } - - var d = Expression.Call (Delegate_CreateDelegate, registrationDelegateType, targetType, Expression.Constant (methodName)); - return Expression.New (JniNativeMethodRegistration_ctor, - Expression.Constant (method), - Expression.Constant (signature), - d); - } - - static void ColorMessage (string message, ConsoleColor color, TextWriter writer, bool writeLine = true) - { - Console.ForegroundColor = color; - if (writeLine) - writer.WriteLine (message); - else - writer.Write (message); - Console.ResetColor (); - } - - public static void ColorWriteLine (string message, ConsoleColor color) => ColorMessage (message, color, Console.Out); - - public static void ColorWrite (string message, ConsoleColor color) => ColorMessage (message, color, Console.Out, false); - - public static void ErrorAndExit (Message message, params object[] args) { - ColorMessage ($"error JM{message.Code:X04}: {Name}: {string.Format (message.Localized, args)}", ConsoleColor.Red, Console.Error); - Environment.Exit (message.Code - 0x4000); - } - - public static void Warning (Message message, params object[] args) => ColorMessage ($"warning JM{message.Code:X04}: {Name}: {string.Format (message.Localized, args)}", ConsoleColor.Yellow, Console.Error); - - public static void Information (string message) => ColorMessage (message, ConsoleColor.Yellow, Console.Out); - - static void AddToTypeMap (TypeDefinition type) - { - typeMap [type.FullName] = type; - - if (!type.HasNestedTypes) - return; - - foreach (var nested in type.NestedTypes) - AddToTypeMap (nested); - } - - static void PrepareTypeMap (ModuleDefinition md) - { - typeMap.Clear (); - - foreach (var type in md.Types) - AddToTypeMap (type); - } - - static TypeDefinition FindType (Type type) - { - TypeDefinition rv; - string cecilName = type.GetCecilName (); - - typeMap.TryGetValue (cecilName, out rv); - - return rv; - } - } - - internal static class Extensions - { - public static string GetCecilName (this Type type) - { - return type.FullName?.Replace ('+', '/'); - } - - static bool CompareTypes (Type reflectionType, TypeReference cecilType) - { - return cecilType.ToString () == reflectionType.GetCecilName (); - } - - static bool MethodsAreEqual (MethodInfo methodInfo, MethodDefinition methodDefinition) - { - if (methodInfo.Name != methodDefinition.Name) - return false; - - if (!CompareTypes (methodInfo.ReturnType, methodDefinition.ReturnType)) - return false; - - - var parameters = methodInfo.GetParameters (); - int infoParametersCount = parameters?.Length ?? 0; - if (!methodDefinition.HasParameters && infoParametersCount == 0) - return true; - - if (infoParametersCount != (methodDefinition.Parameters?.Count ?? 0)) - return false; - - - int i = 0; - foreach (var parameter in methodDefinition.Parameters) { - if (!CompareTypes (parameters [i].ParameterType, parameter.ParameterType)) - return false; - i++; - } - - return true; - } - - internal static Dictionary MethodMap = new Dictionary (); - - public static MethodDefinition GetMethodDefinition (this TypeDefinition td, MethodInfo method) - { - if (MethodMap.TryGetValue (method, out var md)) - return md; - - foreach (var m in td.Methods) - if (MethodsAreEqual (method, m)) { - MethodMap [method] = m; - - return m; - } - - return null; - } - - static bool CheckMethod (MethodDefinition m, ref string name, ref string methodName, ref string signature) - { - var registerAttrs = m.GetCustomAttributes ("Android.Runtime.RegisterAttribute") - .Concat (m.GetCustomAttributes ("Java.Interop.JniMethodSignatureAttribute")); - foreach (var registerAttribute in registerAttrs) { - if (registerAttribute == null || !registerAttribute.HasConstructorArguments) - continue; - - if (registerAttribute.ConstructorArguments.Count < 2) - continue; - - name = registerAttribute.ConstructorArguments [0].Value.ToString (); - signature = registerAttribute.ConstructorArguments [1].Value.ToString (); - - if ((string.IsNullOrEmpty (name) || string.IsNullOrEmpty (signature))) - continue; - - methodName = MarshalMemberBuilder.GetMarshalMethodName (name, signature); - name = $"n_{name}"; - - return true; - } - - return false; - } - - public static bool NeedsMarshalMethod (this MethodDefinition md, DirectoryAssemblyResolver resolver, TypeDefinitionCache cache, MethodInfo method, ref string name, ref string methodName, ref string signature) - { - var m = md; - - while (m != null) { - if (CheckMethod (m, ref name, ref methodName, ref signature)) - return true; - - m = m.GetBaseDefinition (cache); - - if (m == md) - break; - - md = m; - } - - foreach (var iface in method.DeclaringType.GetInterfaces ()) { - if (iface.IsGenericType) - continue; - - var location = iface.Assembly.Location; - var ad = string.IsNullOrEmpty (location) - ? resolver.Resolve (iface.Assembly.GetName ().Name) - : resolver.GetAssembly (location); - - var ifaceMap = method.DeclaringType.GetInterfaceMap (iface); - var id = ad.MainModule.GetType (iface.GetCecilName ()); - - if (id == null) { - App.Warning (Message.WarningCouldntFindInterface, iface.FullName); - continue; - } - - for (int i = 0; i < ifaceMap.TargetMethods.Length; i++) { - if (ifaceMap.TargetMethods [i] == method) { - var imd = id.GetMethodDefinition (ifaceMap.InterfaceMethods [i]); - - if (CheckMethod (imd, ref name, ref methodName, ref signature)) - return true; - } - } - } - - return false; - } - } -} - -class _Jonp_ReferenceCodeGen -{ - static void A (IntPtr jnienv, IntPtr klass, int value) - { - JniRuntime jvm = JniEnvironment.Runtime; - JniRuntime.JniValueManager vm; - - var envp = new JniTransition (jnienv); - try { - vm = jvm.ValueManager; - vm.WaitForGCBridgeProcessing (); - } catch (Exception e) when (jvm.ExceptionShouldTransitionToJni (e)) { - envp.SetPendingException (e); - } finally { - envp.Dispose (); - } - } - - static void B () - { - } - - [JniAddNativeMethodRegistration] - static void RegisterNativeMethods (JniNativeMethodRegistrationArguments args) - { - var methods = new [] { - new JniNativeMethodRegistration ("a", "()V", new Action (A)), - new JniNativeMethodRegistration ("b", "()V", new Action (B)), - }; - args.AddRegistrations (methods); - } -} diff --git a/tools/jnimarshalmethod-gen/Message.cs b/tools/jnimarshalmethod-gen/Message.cs deleted file mode 100644 index 442c175ab..000000000 --- a/tools/jnimarshalmethod-gen/Message.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Java.Interop.Localization; - -namespace Xamarin.Android.Tools.JniMarshalMethodGenerator -{ - class Message - { - public string Localized { get; private set; } - public int Code { get; private set; } - - private Message (int code, string message) { - Localized = message; - Code = code; - } - - public static Message ErrorUnableToPreloadReference = new Message (0x4001, Resources.JniMarshalMethodGen_JM4001); - public static Message ErrorAtLeastOneAssembly = new Message (0x4002, Resources.JniMarshalMethodGen_JM4002); - public static Message ErrorUnableToCreateJavaVM = new Message (0x4003, Resources.JniMarshalMethodGen_JM4003); - public static Message ErrorUnableToReadProfile = new Message (0x4004, Resources.JniMarshalMethodGen_JM4004); - public static Message ErrorPathDoesNotExist = new Message (0x4005, Resources.JniMarshalMethodGen_JM4005); - public static Message ErrorUnableToProcessAssembly = new Message (0x4006, Resources.JniMarshalMethodGen_JM4006); - - public static Message WarningCouldntFindInterface = new Message (0x8001, Resources.JniMarshalMethodGen_JM8001); - public static Message WarningTypeLoadException = new Message (0x8003, Resources.JniMarshalMethodGen_JM8003); - public static Message WarningUnableToFindTypeDefinition = new Message (0x8004, Resources.JniMarshalMethodGen_JM8004); - public static Message WarningMarshalMethodsTypeAlreadyExists = new Message (0x8005, Resources.JniMarshalMethodGen_JM8005); - public static Message WarningUnableToFindMethodDefinition = new Message (0x8006, Resources.JniMarshalMethodGen_JM8006); - public static Message WarningUnableToFindSCWriteLine = new Message (0x8007, Resources.JniMarshalMethodGen_JM8007); - } -} diff --git a/tools/jnimarshalmethod-gen/TypeMover.cs b/tools/jnimarshalmethod-gen/TypeMover.cs deleted file mode 100644 index 6c3336671..000000000 --- a/tools/jnimarshalmethod-gen/TypeMover.cs +++ /dev/null @@ -1,549 +0,0 @@ -using System; -using System.IO; -using System.Collections.Generic; - -using Mono.Cecil; -using Mono.Cecil.Cil; - -using Java.Interop.Tools.Cecil; - -namespace Xamarin.Android.Tools.JniMarshalMethodGenerator -{ - public class TypeMover - { - AssemblyDefinition Source { get; } - AssemblyDefinition Destination { get; } - string DestinationPath { get; } - Dictionary Types { get; } - DirectoryAssemblyResolver Resolver { get; } - - MethodReference consoleWriteLine; - TypeDefinitionCache cache; - - public TypeMover (AssemblyDefinition source, AssemblyDefinition destination, string destinationPath, Dictionary types, DirectoryAssemblyResolver resolver, TypeDefinitionCache cache) - { - Source = source; - Destination = destination; - DestinationPath = destinationPath; - Types = types; - Resolver = resolver; - this.cache = cache; - - if (App.Debug) { - consoleWriteLine = GetSingleParameterMethod (Destination.MainModule, "mscorlib", "System.Console", "WriteLine", "System.String"); - if (consoleWriteLine == null) { - App.Warning (Message.WarningUnableToFindSCWriteLine); - App.Debug = false; - } - } - } - - public void Move () - { - int movedTypesCount = 0; - - typeMap.Clear (); - resolvedTypeMap.Clear (); - - foreach (var type in Types.Values) { - Move (type); - movedTypesCount++; - } - - if (movedTypesCount <= 0) { - if (App.Verbose) - App.Information ("No type was moved => nothing to write, no new assembly created."); - return; - } - - Destination.Write (DestinationPath, new WriterParameters () { WriteSymbols = Destination.MainModule.HasSymbols }); - - if (App.Verbose) - App.ColorWriteLine ($"Wrote updated {Destination.MainModule.FileName} assembly", ConsoleColor.Cyan); - } - - public static readonly string NestedName = "__<$>_jni_marshal_methods"; - - Dictionary newHelperMethods; - - bool TypeIsEmptyOrHasOnlyDefaultConstructor (TypeDefinition type) - { - return !type.HasMethods || (type.Methods.Count == 1 && type.Methods [0].IsConstructor); - } - - void Move (Type type) - { - var typeSrc = Source.MainModule.GetType (type.GetCecilName ()); - var typeDst = Destination.MainModule.GetType (type.GetCecilName ()); - - List toRemove = null; - foreach (var nestedType in typeDst.NestedTypes) { - if (nestedType.Name == NestedName) { - if (toRemove == null) - toRemove = new List (); - - toRemove.Add (nestedType); - } - } - - if (toRemove != null) { - foreach (var t in toRemove) { - App.ColorWriteLine ($"Removing original '{t.GetAssemblyQualifiedName (cache)}' type. (forced)", ConsoleColor.Cyan); - typeDst.NestedTypes.Remove (t); - } - } - - var jniType = new TypeDefinition ("", NestedName, TypeAttributes.NestedPrivate | TypeAttributes.Sealed); - - if (TypeIsEmptyOrHasOnlyDefaultConstructor (typeSrc)) - return; - - if (App.Verbose) { - Console.Write ($"Moving type "); - App.ColorWrite ($"{typeSrc.FullName},{typeSrc.Module.FileName}", ConsoleColor.Yellow); - Console.Write (" to "); - App.ColorWriteLine ($"{Destination.MainModule.FileName}", ConsoleColor.Yellow); - } - - jniType.BaseType = GetUpdatedType (typeSrc.BaseType, Destination.MainModule); - typeDst.NestedTypes.Add (jniType); - - - newHelperMethods = new Dictionary (); - - foreach (var m in typeSrc.Methods) { - if (m.Name == "__RegisterNativeMembers") - continue; - var newMethod = Duplicate (m, Destination.MainModule, typeDst); - AddMethod (jniType, newMethod); - - newHelperMethods [newMethod.Name] = newMethod; - } - - foreach (var m in typeSrc.Methods) { - if (m.Name != "__RegisterNativeMembers") - continue; - - AddMethod (jniType, Duplicate (m, Destination.MainModule, typeDst)); - } - } - - void AddMethod (TypeDefinition type, MethodDefinition method) - { - type.Methods.Add (method); - - if (App.Verbose) { - Console.Write ("Moved method "); - App.ColorWriteLine ($"{method}", ConsoleColor.Green); - } - } - - static Dictionary typeMap = new Dictionary (); - static Dictionary resolvedTypeMap = new Dictionary (); - - static TypeDefinition Resolve (TypeReference type) - { - if (resolvedTypeMap.ContainsKey (type)) - return resolvedTypeMap [type]; - - var resolved = type.Resolve (); - - resolvedTypeMap [type] = resolved; - - return resolved; - } - - static TypeReference GetUpdatedArray (TypeReference type, TypeReference newReference) - { - if (!type.IsArray) - return type; - - var t = type; - var stack = new Stack (); - - do { - var ta = t as ArrayType; - - stack.Push (ta); - t = ta.ElementType; - } while (t.IsArray); - - while (stack.Count > 0) { - var ta = stack.Pop (); - var na = new ArrayType (newReference, ta.Rank); - - if (ta.Rank > 1) { - for (int i = 0; i < ta.Rank; i++) { - na.Dimensions [i] = ta.Dimensions [i]; - } - } - - newReference = na; - } - - return newReference; - } - - static TypeReference GetUpdatedType (TypeReference type, ModuleDefinition module) - { - if (typeMap.ContainsKey (type)) - return typeMap [type]; - - if (type is GenericInstanceType giType) - return GetUpdatedGenericType (giType, module); - - var td = Resolve (type); - - var tr = td.Module.FileName != module.FileName - ? module.ImportReference (type) - : module.GetType (td.FullName); - - if (type.IsArray && td.Module.FileName == module.FileName) - tr = GetUpdatedArray (type, tr); - - typeMap [type] = tr; - - return tr; - } - - static TypeReference GetUpdatedGenericType (GenericInstanceType type, ModuleDefinition module) - { - if (typeMap.ContainsKey (type)) - return typeMap [type]; - - var td = Resolve (type); - var newType = new GenericInstanceType (GetUpdatedType (td, module)); - - if (type.HasGenericArguments) - foreach (var ga in type.GenericArguments) - newType.GenericArguments.Add (GetUpdatedType (ga, module)); - - if (type.HasGenericParameters) - foreach (var gp in type.GenericParameters) - newType.GenericParameters.Add (gp); - - var tr = td.Module.FileName != module.FileName - ? module.ImportReference (newType) - : module.GetType (newType.FullName); - - if (type.IsArray) - tr = GetUpdatedArray (type.ElementType, tr); - - typeMap [type] = tr; - - return tr; - } - - - static Dictionary methodMap = new Dictionary (); - static Dictionary resolvedMethodMap = new Dictionary (); - - static MethodDefinition ResolveMethod (MethodReference method) - { - if (resolvedMethodMap.ContainsKey (method)) - return resolvedMethodMap [method]; - - var resolved = method.Resolve (); - - resolvedMethodMap [method] = resolved; - - return resolved; - } - - static MethodReference GetUpdatedMethod (MethodReference method, ModuleDefinition module) - { - if (methodMap.ContainsKey (method)) - return methodMap [method]; - - MethodDefinition md = ResolveMethod (method.IsGenericInstance ? (method as GenericInstanceMethod).ElementMethod : method); - MethodReference mr; - - if (method.IsGenericInstance) { - var newGenericMethod = new GenericInstanceMethod (md); - - var genericInstance = method as GenericInstanceMethod; - if (genericInstance.HasGenericArguments) - foreach (var ga in genericInstance.GenericArguments) - newGenericMethod.GenericArguments.Add (GetUpdatedType (ga, module)); - - mr = module.ImportReference (newGenericMethod); - } else - mr = module.ImportReference (md.Module != null && md.Module.FileName == module.FileName ? md : method); - - foreach (var p in mr.Parameters) - p.ParameterType = GetUpdatedType (p.ParameterType, module); - - if (method.DeclaringType != null && !method.DeclaringType.HasGenericParameters) - methodMap [method] = mr; - - return mr; - } - - static FieldReference GetUpdatedField (FieldReference fr, ModuleDefinition module) - { - FieldReference newField = new FieldReference (fr.Name, GetUpdatedType (fr.FieldType, module)); - newField.DeclaringType = GetUpdatedType (fr.DeclaringType, module); - - return newField; - } - - Instruction GetUpdatedInstruction (Instruction il, ModuleDefinition module) - { - if (il.Operand == null) - return Instruction.Create (il.OpCode); - - if (il.Operand is MethodReference mr) - return Instruction.Create (il.OpCode, GetUpdatedMethod (mr, module)); - - if (il.Operand is GenericInstanceType giType) - return Instruction.Create (il.OpCode, GetUpdatedGenericType (giType, module)); - - if (il.Operand is TypeReference tr) - return Instruction.Create (il.OpCode, GetUpdatedType (tr, module)); - - if (il.Operand is FieldReference fr) - return Instruction.Create (il.OpCode, GetUpdatedField (fr, module)); - - return il; - } - - static ExceptionHandler GetUpdatedExceptionHandler (ExceptionHandler eh, Dictionary instructionMap, ModuleDefinition module) - { - var handler = new ExceptionHandler (eh.HandlerType); - - if (handler.CatchType != null) - handler.CatchType = GetUpdatedType (eh.CatchType, module); - - if (eh.TryStart != null) - handler.TryStart = instructionMap [eh.TryStart]; - - if (eh.TryEnd != null) - handler.TryEnd = instructionMap [eh.TryEnd]; - - if (eh.FilterStart != null) - handler.FilterStart = instructionMap [eh.FilterStart]; - - if (eh.HandlerStart != null) - handler.HandlerStart = instructionMap [eh.HandlerStart]; - - if (eh.HandlerEnd != null) - handler.HandlerEnd = instructionMap [eh.HandlerEnd]; - - return handler; - } - - MethodReference GetActionConstructor (TypeReference type, ModuleDefinition module) - { - var td = Resolve (type); - if (!td.HasMethods) - return null; - - foreach (var m in td.Methods) { - if (m.IsConstructor && m.HasParameters && m.Parameters.Count == 2 && m.Parameters [0].ParameterType.FullName == "System.Object" && m.Parameters [1].ParameterType.FullName == "System.IntPtr") { - var mr = GetUpdatedMethod (m, module); - if (type is GenericInstanceType) - mr.DeclaringType = type; - return mr; - } - } - return null; - } - - bool AnalyzeAndImprove (Mono.Collections.Generic.Collection instructions, Mono.Collections.Generic.Collection newInstructions, int idx, string typeName, out int skipCount, ModuleDefinition module) - { - var idxStart = idx; - var il = instructions [idx++]; - - skipCount = 0; - - if (il.OpCode == OpCodes.Ldstr && il.Operand is string opStr && opStr != null && opStr == typeName) { - il = instructions [idx++]; - if (il.OpCode != OpCodes.Call || !(il.Operand is MethodReference opMR) || opMR.Name != "GetType" || opMR.DeclaringType.FullName != "System.Type") - return false; - - il = instructions [idx++]; - if (il.OpCode != OpCodes.Stloc_0) - return false; - - skipCount = 2; - - if (App.Debug) { - newInstructions.Add (Instruction.Create (OpCodes.Ldstr, $"Registering JNI marshal methods in {opStr}")); - newInstructions.Add (Instruction.Create (OpCodes.Call, module.ImportReference (consoleWriteLine))); - } - - return true; - } - - if (il.OpCode == OpCodes.Dup && instructions.Count > idxStart + 10) { - il = instructions [idx++]; - if (!il.OpCode.ToString ().StartsWith ("ldc.i4", StringComparison.InvariantCulture)) - return false; - - il = instructions [idx++]; - if (il.OpCode != OpCodes.Ldstr) - return false; - - il = instructions [idx++]; - if (il.OpCode != OpCodes.Ldstr) - return false; - - MethodReference constructor; - TypeReference delegateType; - var customDelegate = false; - il = instructions [idx++]; - if (il.OpCode == OpCodes.Ldstr && il.Operand is string delegateTypeName) { - il = instructions [idx++]; - if (!il.OpCode.ToString ().StartsWith ("ldc.i4", StringComparison.InvariantCulture)) - return false; - - il = instructions [idx++]; - if (il.OpCode != OpCodes.Call || !(il.Operand is MethodReference opMR2) || opMR2.Name != "GetType") - return false; - - delegateType = module.GetType (delegateTypeName); - if (delegateType == null) { - var t = Type.GetType (delegateTypeName); - if (t == null) - return false; - - delegateType = GetType (t.Assembly.GetName ().ToString (), delegateTypeName); - if (delegateType == null) - return false; - } - - skipCount = 11; - customDelegate = true; - } else if (il.OpCode == OpCodes.Ldtoken && il.Operand is TypeReference) { - delegateType = GetUpdatedType (il.Operand as TypeReference, module); - - il = instructions [idx++]; - if (il.OpCode != OpCodes.Call || !(il.Operand is MethodReference opMR2) || opMR2.Name != "GetTypeFromHandle") - return false; - - skipCount = 10; - } else - return false; - - constructor = GetActionConstructor (delegateType, module); - if (constructor == null) - return false; - - il = instructions [idx++]; - if (il.OpCode != OpCodes.Ldloc_0) - return false; - - il = instructions [idx++]; - if (il.OpCode != OpCodes.Ldstr) - return false; - - var methodName = il.Operand as string; - if (string.IsNullOrEmpty (methodName)) - return false; - - il = instructions [idx++]; - if (il.OpCode != OpCodes.Call || !(il.Operand is MethodReference opMR3) || opMR3.Name != "CreateDelegate") - return false; - - il = instructions [idx++]; - if (il.OpCode != OpCodes.Newobj) - return false; - - il = instructions [idx++]; - if (il.OpCode != OpCodes.Stelem_Any) - return false; - - idx = idxStart; - for (int i = 0; i < 4; i++) - newInstructions.Add (GetUpdatedInstruction (instructions [idx++], module)); - - newInstructions.Add (Instruction.Create (OpCodes.Ldnull)); - newInstructions.Add (Instruction.Create (OpCodes.Ldftn, newHelperMethods?[methodName])); - newInstructions.Add (Instruction.Create (OpCodes.Newobj, constructor)); - - idx += customDelegate ? 6 : 5; - for (int i = 0; i < 2; i++) - newInstructions.Add (GetUpdatedInstruction (instructions [idx++], module)); - - return true; - } - - return false; - } - - MethodDefinition Duplicate (MethodDefinition src, ModuleDefinition module, TypeDefinition type) - { - var md = new MethodDefinition (src.Name, src.Attributes, GetUpdatedType (src.ReturnType, module)); - - if (src.HasCustomAttributes) - foreach (var ca in src.CustomAttributes) - md.CustomAttributes.Add (new CustomAttribute (GetUpdatedMethod (ca.Constructor, module), ca.GetBlob ())); - - foreach (var p in src.Parameters) - md.Parameters.Add (new ParameterDefinition (p.Name, p.Attributes, GetUpdatedType (p.ParameterType, module))); - - md.Body.InitLocals = src.Body.InitLocals; - - var instructionMap = new Dictionary (); - var instructions = src.Body.Instructions; - var newInstructions = md.Body.Instructions; - var count = instructions.Count; - var typeName = type.FullName.Replace ('/', '+'); - var isRegisterMethod = src.Name == "__RegisterNativeMembers"; - int skipCount; - int improvements = 0; - bool failed = false; - - for (int i = 0; i < count; i++) { - var il = instructions [i]; - bool result = false; - - if (isRegisterMethod && (result = AnalyzeAndImprove (instructions, newInstructions, i, typeName, out skipCount, module))) { - i += skipCount; - improvements++; - } else { - failed |= !result; - Instruction newInstruction = GetUpdatedInstruction (il, module); - newInstructions.Add (newInstruction); - instructionMap [il] = newInstruction; - } - } - - if (src.Body.HasVariables) - foreach (var v in src.Body.Variables) - if (!isRegisterMethod || failed || v.VariableType.FullName != "System.Type") - md.Body.Variables.Add (new VariableDefinition (GetUpdatedType (v.VariableType, module))); - - - if (isRegisterMethod && improvements < 2) - App.Information ($"Method {md} was not improved. There should have been at least 2 performance improvements in this registration method."); - - if (src.Body.HasExceptionHandlers) - foreach (var eh in src.Body.ExceptionHandlers) - md.Body.ExceptionHandlers.Add (GetUpdatedExceptionHandler (eh, instructionMap, module)); - - md.Body.MaxStackSize = src.Body.MaxStackSize; - - return md; - } - - TypeDefinition GetType (string assemblyName, string typeName) - { - var assembly = Resolver.Resolve (assemblyName); - if (assembly == null) - return null; - - return assembly.MainModule.GetType (typeName); - } - - MethodReference GetSingleParameterMethod (ModuleDefinition module, string assemblyName, string typeName, string methodName, string parameterTypeName) - { - var typeTD = GetType (assemblyName, typeName); - foreach (var md in typeTD.Methods) - if (md.Name == methodName && md.HasParameters && md.Parameters.Count == 1 && md.Parameters [0].ParameterType.FullName == parameterTypeName) - return GetUpdatedMethod (md, module); - - return null; - } - } -} diff --git a/tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csproj b/tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csproj deleted file mode 100644 index 1907cdde8..000000000 --- a/tools/jnimarshalmethod-gen/Xamarin.Android.Tools.JniMarshalMethodGenerator.csproj +++ /dev/null @@ -1,40 +0,0 @@ - - - - $(DotNetTargetFramework) - Exe - jnimarshalmethod-gen - - - - - - - - $(UtilityOutputFullPath) - <_DumpRegisterNativeMembers>True - - - - _DUMP_REGISTER_NATIVE_MEMBERS;$(DefineConstants) - - - - - - - - - - - - - - - - - - - - - From 5cb82cdca15dcc84ad4a1a23c05aa4cf852381d9 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 17 Apr 2026 08:45:32 -0500 Subject: [PATCH 2/5] Fix CI failures: restore JreTypeManager fallback, fix MonoRuntimeValueManager trim warnings - JreTypeManager: Simplify RegisterNativeMembers to return early when methods is empty (types like JavaProxyThrowable register with no methods), and throw for non-empty methods without static registration. - MonoRuntimeValueManager: Add trim suppression attributes for GetUninitializedObject call to fix NativeAOT publish errors. - Java.Base-Tests: Add explicit marshal methods and static registration to MyRunnable and MyIntConsumer test types, since dynamic marshal method generation via MarshalMemberBuilder is no longer available. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Java.Interop/JreTypeManager.cs | 4 ++ .../Java.Interop/MonoRuntimeValueManager.cs | 11 +++- .../Java.Base/JavaToManagedTests.cs | 50 +++++++++++++++++++ 3 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs b/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs index 7dc315d52..128ddb626 100644 --- a/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs +++ b/src/Java.Runtime.Environment/Java.Interop/JreTypeManager.cs @@ -59,6 +59,10 @@ public override void RegisterNativeMembers ( return; } + if (methods.IsEmpty) { + return; + } + throw new NotSupportedException ( $"Could not register native members for type '{type.FullName}'. " + "Ensure that the type has the appropriate [JniAddNativeMethodRegistration] attribute and static registration method."); diff --git a/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs b/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs index 0fcf1fa79..2953c799a 100644 --- a/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs +++ b/src/Java.Runtime.Environment/Java.Interop/MonoRuntimeValueManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; @@ -257,15 +258,23 @@ static Exception CreateJniLocationException () } } + const string NotUsedInAndroid = "This code path is not used in Android projects."; + public override void ActivatePeer (IJavaPeerable? self, JniObjectReference reference, ConstructorInfo cinfo, object?[]? argumentValues) { var runtime = JniEnvironment.Runtime; try { var declType = cinfo.DeclaringType ?? throw new NotSupportedException ("Do not know the type to create!"); - var instance = (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (declType); + var instance = GetUninitializedObject (declType); instance.SetPeerReference (reference); cinfo.Invoke (instance, argumentValues); + + // FIXME: https://github.com/dotnet/java-interop/issues/1192 + [UnconditionalSuppressMessage ("Trimming", "IL2067", Justification = NotUsedInAndroid)] + [UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = NotUsedInAndroid)] + static IJavaPeerable GetUninitializedObject (Type type) => + (IJavaPeerable) System.Runtime.CompilerServices.RuntimeHelpers.GetUninitializedObject (type); } catch (Exception e) { var m = string.Format ("Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.", reference, diff --git a/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs b/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs index f3580b49c..af5d5bc19 100644 --- a/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs +++ b/tests/Java.Base-Tests/Java.Base/JavaToManagedTests.cs @@ -63,10 +63,35 @@ public MyRunnable (Action action) this.action = action; } + [JniMethodSignature ("run", "()V")] public void Run () { action (); } + + static Delegate GetRunHandler () + { + return new _JniMarshal_PPV_V (n_Run); + } + + delegate void _JniMarshal_PPV_V (IntPtr jnienv, IntPtr n_self); + + static void n_Run (IntPtr jnienv, IntPtr n_self) + { + var r_self = new JniObjectReference (n_self); + var self = JniEnvironment.Runtime.ValueManager.GetValue (ref r_self, JniObjectReferenceOptions.CopyAndDoNotRegister); + try { + self!.Run (); + } finally { + self?.DisposeUnlessReferenced (); + } + } + + [JniAddNativeMethodRegistration] + static void RegisterNativeMembers (JniNativeMethodRegistrationArguments args) + { + args.AddRegistrations (new [] { new JniNativeMethodRegistration ("n_run", "()V", new _JniMarshal_PPV_V (n_Run)) }); + } } [JniTypeSignature ("example/MyIntConsumer")] @@ -79,9 +104,34 @@ public MyIntConsumer (Action action) this.action = action; } + [JniMethodSignature ("accept", "(I)V")] public void Accept (int value) { action (value); } + + static Delegate GetAcceptHandler () + { + return new _JniMarshal_PPIV_V (n_Accept); + } + + delegate void _JniMarshal_PPIV_V (IntPtr jnienv, IntPtr n_self, int value); + + static void n_Accept (IntPtr jnienv, IntPtr n_self, int value) + { + var r_self = new JniObjectReference (n_self); + var self = JniEnvironment.Runtime.ValueManager.GetValue (ref r_self, JniObjectReferenceOptions.CopyAndDoNotRegister); + try { + self!.Accept (value); + } finally { + self?.DisposeUnlessReferenced (); + } + } + + [JniAddNativeMethodRegistration] + static void RegisterNativeMembers (JniNativeMethodRegistrationArguments args) + { + args.AddRegistrations (new [] { new JniNativeMethodRegistration ("n_accept", "(I)V", new _JniMarshal_PPIV_V (n_Accept)) }); + } } } From be1d3411e9a22de7072a336370e5d1113f38757c Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 17 Apr 2026 11:58:14 -0500 Subject: [PATCH 3/5] Fix Hello-NativeAOTFromJNI: replace [JavaCallable] with explicit marshal methods ManagedType.cs used [JavaCallable] attributes which relied on the now-removed jnimarshalmethod-gen tool. Replace with explicit n_* marshal methods and [JniAddNativeMethodRegistration] static registration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../JavaCallableAttributes.cs | 32 ------------------- samples/Hello-NativeAOTFromJNI/ManagedType.cs | 31 ++++++++++++++++-- 2 files changed, 29 insertions(+), 34 deletions(-) delete mode 100644 samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.cs diff --git a/samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.cs b/samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.cs deleted file mode 100644 index b930761f4..000000000 --- a/samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.cs +++ /dev/null @@ -1,32 +0,0 @@ -#nullable enable -using System; - -namespace Java.Interop { - - [AttributeUsage (AttributeTargets.Method, AllowMultiple=false)] - public sealed class JavaCallableAttribute : Attribute { - - public JavaCallableAttribute () - { - } - - public JavaCallableAttribute (string? name) - { - Name = name; - } - - public string? Name {get; private set;} - public string? Signature {get; set;} - } - - [AttributeUsage (AttributeTargets.Constructor, AllowMultiple=false)] - public sealed class JavaCallableConstructorAttribute : Attribute { - - public JavaCallableConstructorAttribute () - { - } - - public string? SuperConstructorExpression {get; set;} - public string? Signature {get; set;} - } -} diff --git a/samples/Hello-NativeAOTFromJNI/ManagedType.cs b/samples/Hello-NativeAOTFromJNI/ManagedType.cs index 3d21f7163..1284a5209 100644 --- a/samples/Hello-NativeAOTFromJNI/ManagedType.cs +++ b/samples/Hello-NativeAOTFromJNI/ManagedType.cs @@ -1,12 +1,12 @@ namespace Example; +using System; using Java.Interop; [JniTypeSignature (JniTypeName)] class ManagedType : Java.Lang.Object { internal const string JniTypeName = "example/ManagedType"; - [JavaCallableConstructor(SuperConstructorExpression="")] public ManagedType (int value) { this.value = value; @@ -14,9 +14,36 @@ public ManagedType (int value) int value; - [JavaCallable ("getString")] public Java.Lang.String GetString () { return new Java.Lang.String ($"Hello from C#, via Java.Interop! Value={value}"); } + + delegate IntPtr _JniMarshal_PP_L (IntPtr jnienv, IntPtr n_self); + + static Delegate GetGetStringHandler () + { + return new _JniMarshal_PP_L (n_GetString); + } + + static IntPtr n_GetString (IntPtr jnienv, IntPtr n_self) + { + var r_self = new JniObjectReference (n_self); + var self = JniEnvironment.Runtime.ValueManager.GetValue (ref r_self, JniObjectReferenceOptions.CopyAndDoNotRegister); + try { + var result = self!.GetString (); + var r = result.PeerReference.NewLocalRef (); + return JniEnvironment.References.NewReturnToJniRef (r); + } finally { + self?.DisposeUnlessReferenced (); + } + } + + [JniAddNativeMethodRegistration] + static void RegisterNativeMembers (JniNativeMethodRegistrationArguments args) + { + args.AddRegistrations (new [] { + new JniNativeMethodRegistration ("n_GetString", "()Ljava/lang/String;", new _JniMarshal_PP_L (n_GetString)), + }); + } } From 20e8ad182f410be96b4dd798983829cda5dbf2f2 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Fri, 17 Apr 2026 16:01:11 -0500 Subject: [PATCH 4/5] Restore [JavaCallable] attributes for Hello-NativeAOTFromJNI JCW generation jcw-gen uses Cecil to find [JavaCallable] and [JavaCallableConstructor] by attribute name to emit Java-side methods. These attributes must still exist at compile time for the JCW to include getString() and the constructor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../JavaCallableAttributes.cs | 32 +++++++++++++++++++ samples/Hello-NativeAOTFromJNI/ManagedType.cs | 7 ++-- 2 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.cs diff --git a/samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.cs b/samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.cs new file mode 100644 index 000000000..b930761f4 --- /dev/null +++ b/samples/Hello-NativeAOTFromJNI/JavaCallableAttributes.cs @@ -0,0 +1,32 @@ +#nullable enable +using System; + +namespace Java.Interop { + + [AttributeUsage (AttributeTargets.Method, AllowMultiple=false)] + public sealed class JavaCallableAttribute : Attribute { + + public JavaCallableAttribute () + { + } + + public JavaCallableAttribute (string? name) + { + Name = name; + } + + public string? Name {get; private set;} + public string? Signature {get; set;} + } + + [AttributeUsage (AttributeTargets.Constructor, AllowMultiple=false)] + public sealed class JavaCallableConstructorAttribute : Attribute { + + public JavaCallableConstructorAttribute () + { + } + + public string? SuperConstructorExpression {get; set;} + public string? Signature {get; set;} + } +} diff --git a/samples/Hello-NativeAOTFromJNI/ManagedType.cs b/samples/Hello-NativeAOTFromJNI/ManagedType.cs index 1284a5209..cea67b0f7 100644 --- a/samples/Hello-NativeAOTFromJNI/ManagedType.cs +++ b/samples/Hello-NativeAOTFromJNI/ManagedType.cs @@ -7,6 +7,7 @@ namespace Example; class ManagedType : Java.Lang.Object { internal const string JniTypeName = "example/ManagedType"; + [JavaCallableConstructor (SuperConstructorExpression="")] public ManagedType (int value) { this.value = value; @@ -14,6 +15,7 @@ public ManagedType (int value) int value; + [JavaCallable ("getString")] public Java.Lang.String GetString () { return new Java.Lang.String ($"Hello from C#, via Java.Interop! Value={value}"); @@ -21,11 +23,6 @@ public Java.Lang.String GetString () delegate IntPtr _JniMarshal_PP_L (IntPtr jnienv, IntPtr n_self); - static Delegate GetGetStringHandler () - { - return new _JniMarshal_PP_L (n_GetString); - } - static IntPtr n_GetString (IntPtr jnienv, IntPtr n_self) { var r_self = new JniObjectReference (n_self); From b7cb4f269457b34a5a4ad2bf0e737423919f4b78 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 20 Apr 2026 08:20:33 -0500 Subject: [PATCH 5/5] Add [UnmanagedFunctionPointer] to NativeAOT sample delegate NativeAOT requires delegate types used for JNI callbacks to have [UnmanagedFunctionPointer] for proper marshalling data generation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- samples/Hello-NativeAOTFromJNI/ManagedType.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/samples/Hello-NativeAOTFromJNI/ManagedType.cs b/samples/Hello-NativeAOTFromJNI/ManagedType.cs index cea67b0f7..2c2d1f42c 100644 --- a/samples/Hello-NativeAOTFromJNI/ManagedType.cs +++ b/samples/Hello-NativeAOTFromJNI/ManagedType.cs @@ -21,6 +21,7 @@ public Java.Lang.String GetString () return new Java.Lang.String ($"Hello from C#, via Java.Interop! Value={value}"); } + [System.Runtime.InteropServices.UnmanagedFunctionPointer (System.Runtime.InteropServices.CallingConvention.Winapi)] delegate IntPtr _JniMarshal_PP_L (IntPtr jnienv, IntPtr n_self); static IntPtr n_GetString (IntPtr jnienv, IntPtr n_self)