Skip to content

Commit 0109801

Browse files
[release/8.0] [mono] Initialize module's image ALC for dynamic objects (#90912)
* Use the image's ALC instead of the default one if exists * Init module's image ALC * Add runtime test for dynamic objects * Fix lint * Disable test on platforms that don't support dynamic code generation --------- Co-authored-by: Milos Kotlar <[email protected]>
1 parent a2b869c commit 0109801

File tree

4 files changed

+125
-0
lines changed

4 files changed

+125
-0
lines changed

src/mono/mono/metadata/sre.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,6 +1289,7 @@ image_module_basic_init (MonoReflectionModuleBuilderHandle moduleb, MonoError *e
12891289
* determined at assembly save time.
12901290
*/
12911291
/*image = (MonoDynamicImage*)ab->dynamic_assembly->assembly.image; */
1292+
MonoAssemblyLoadContext *alc = mono_alc_get_default ();
12921293
MonoStringHandle abname = MONO_HANDLE_NEW_GET (MonoString, ab, name);
12931294
char *name = mono_string_handle_to_utf8 (abname, error);
12941295
return_val_if_nok (error, FALSE);
@@ -1300,6 +1301,7 @@ image_module_basic_init (MonoReflectionModuleBuilderHandle moduleb, MonoError *e
13001301
}
13011302
MonoDynamicAssembly *dynamic_assembly = MONO_HANDLE_GETVAL (ab, dynamic_assembly);
13021303
image = mono_dynamic_image_create (dynamic_assembly, name, fqname);
1304+
image->image.alc = alc;
13031305

13041306
MONO_HANDLE_SETVAL (MONO_HANDLE_CAST (MonoReflectionModule, moduleb), image, MonoImage*, &image->image);
13051307
MONO_HANDLE_SETVAL (moduleb, dynamic_image, MonoDynamicImage*, image);
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System;
2+
using System.Resources;
3+
using System.Reflection;
4+
using System.Reflection.Emit;
5+
using System.ComponentModel.DataAnnotations;
6+
using System.Linq;
7+
8+
using Xunit;
9+
10+
#nullable disable
11+
12+
namespace DynamicObjects {
13+
public class M {
14+
public const string ObjectRequiredMessage = "some string";
15+
public static int Main() {
16+
var instance = createObject();
17+
var attrs = instance.GetType().GetProperty("prop1").GetCustomAttributes();
18+
19+
Assert.True(attrs.Count() == 2);
20+
Assert.Equal(attrs.ElementAt(0).ToString(), "System.ComponentModel.DataAnnotations.DisplayAttribute");
21+
Assert.Equal(attrs.ElementAt(1).ToString(), "System.ComponentModel.DataAnnotations.RequiredAttribute");
22+
Assert.Equal(typeof(RequiredAttribute), attrs.ElementAt(1).GetType());
23+
Assert.Equal(ObjectRequiredMessage, ((RequiredAttribute)attrs.ElementAt(1)).FormatErrorMessage("abc"));
24+
25+
Console.WriteLine("Success");
26+
return 100;
27+
}
28+
29+
public static object createObject () {
30+
var an = new AssemblyName { Name = "TempAssembly" ,Version = new Version(1, 0, 0, 0) };
31+
var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
32+
var moduleBuilder = assemblyBuilder.DefineDynamicModule("TempWorkflowAssembly.dll");
33+
var tb = moduleBuilder.DefineType("namespace.myclass"
34+
, TypeAttributes.Public |
35+
TypeAttributes.Class |
36+
TypeAttributes.AnsiClass |
37+
TypeAttributes.BeforeFieldInit
38+
, typeof(object));
39+
40+
FieldBuilder fb = tb.DefineField("_prop1",
41+
typeof(string),
42+
FieldAttributes.Private);
43+
44+
var pb = tb.DefineProperty("prop1", PropertyAttributes.HasDefault, typeof(string), null);
45+
MethodAttributes getSetAttr =
46+
MethodAttributes.Public | MethodAttributes.SpecialName |
47+
MethodAttributes.HideBySig;
48+
49+
// Define the "get" accessor method for prop1.
50+
MethodBuilder custNameGetPropMthdBldr =
51+
tb.DefineMethod("get_prop1",
52+
getSetAttr,
53+
typeof(string),
54+
Type.EmptyTypes);
55+
56+
ILGenerator custNameGetIL = custNameGetPropMthdBldr.GetILGenerator();
57+
58+
custNameGetIL.Emit(OpCodes.Ldarg_0);
59+
custNameGetIL.Emit(OpCodes.Ldfld, fb);
60+
custNameGetIL.Emit(OpCodes.Ret);
61+
62+
// Define the "set" accessor method for prop1.
63+
MethodBuilder custNameSetPropMthdBldr =
64+
tb.DefineMethod("set_prop1",
65+
getSetAttr,
66+
null,
67+
new Type[] { typeof(string) });
68+
69+
ILGenerator custNameSetIL = custNameSetPropMthdBldr.GetILGenerator();
70+
71+
custNameSetIL.Emit(OpCodes.Ldarg_0);
72+
custNameSetIL.Emit(OpCodes.Ldarg_1);
73+
custNameSetIL.Emit(OpCodes.Stfld, fb);
74+
custNameSetIL.Emit(OpCodes.Ret);
75+
76+
// Last, we must map the two methods created above to our PropertyBuilder to
77+
// their corresponding behaviors, "get" and "set" respectively.
78+
pb.SetGetMethod(custNameGetPropMthdBldr);
79+
pb.SetSetMethod(custNameSetPropMthdBldr);
80+
81+
82+
///create display attribute
83+
var dat = typeof(DisplayAttribute);
84+
CustomAttributeBuilder CAB = new CustomAttributeBuilder(dat.GetConstructor(new Type[0]),
85+
new object[0],
86+
new PropertyInfo[1] { dat.GetProperty(nameof(DisplayAttribute.Name))},
87+
new object[] { "property 1"});
88+
pb.SetCustomAttribute(CAB);
89+
90+
// //create required attribute
91+
var rat = typeof(RequiredAttribute);
92+
CustomAttributeBuilder CABR = new CustomAttributeBuilder(rat.GetConstructor(new Type[0]),
93+
new object[0],
94+
new PropertyInfo[2] { rat.GetProperty(nameof(RequiredAttribute.ErrorMessageResourceType)),rat.GetProperty(nameof(RequiredAttribute.ErrorMessageResourceName))},
95+
new object[] {typeof(ValidationErrors), "ObjectRequired" });
96+
pb.SetCustomAttribute(CABR);
97+
98+
var objectType = tb.CreateType();
99+
return Activator.CreateInstance(objectType);
100+
}
101+
}
102+
103+
public class ValidationErrors {
104+
public static string ObjectRequired => M.ObjectRequiredMessage;
105+
}
106+
107+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<Compile Include="$(MSBuildProjectName).cs" />
7+
<ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
8+
</ItemGroup>
9+
</Project>

src/tests/issues.targets

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,10 @@
11771177

11781178
<!-- Requires Debug build -->
11791179
<ExcludeList Include="$(XunitTestBinBase)/JIT\Directed\debugging\poisoning\poison\*" />
1180+
1181+
<ExcludeList Include="$(XunitTestBinBase)/Loader/CustomAttributes/**">
1182+
<Issue>Dynamic code generation is not supported on this platform</Issue>
1183+
</ExcludeList>
11801184
</ItemGroup>
11811185

11821186
<!-- run.proj finds all the *.cmd/*.sh scripts in a test folder and creates corresponding test methods.
@@ -3717,6 +3721,9 @@
37173721
<ExcludeList Include="$(XunitTestBinBase)/tracing/eventpipe/gcdump/**">
37183722
<Issue>https://github.com/dotnet/runtime/issues/90012</Issue>
37193723
</ExcludeList>
3724+
<ExcludeList Include="$(XunitTestBinBase)/Loader/CustomAttributes/**">
3725+
<Issue>Dynamic code generation is not supported on this platform</Issue>
3726+
</ExcludeList>
37203727
</ItemGroup>
37213728

37223729
<ItemGroup Condition="'$(TargetArchitecture)' == 'wasm' or '$(TargetsMobile)' == 'true'">

0 commit comments

Comments
 (0)