Skip to content

Commit 9fbdab3

Browse files
authored
Improve AOT usage scenarios with metadata (#1764)
* create AOT example project * set REPL for AOT publish * extract reflection related helpers from TypeConverter to InteropHelper
1 parent 0946a9f commit 9fbdab3

34 files changed

+595
-406
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<IsPackable>false</IsPackable>
9+
<PublishAot>true</PublishAot>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<ProjectReference Include="..\Jint\Jint.csproj" />
14+
<TrimmerRootAssembly Include="Jint" />
15+
</ItemGroup>
16+
17+
</Project>

Jint.AotExample/Program.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using Jint;
2+
3+
var engine = new Engine(cfg => cfg
4+
.AllowClr()
5+
);
6+
7+
engine.SetValue("company", new Company());
8+
9+
Console.WriteLine($"Company's name: {engine.Evaluate("company.name")}");
10+
Console.WriteLine($"Company's field: {engine.Evaluate("company.field")}");
11+
Console.WriteLine($"Company's indexer: {engine.Evaluate("company[42]")}");
12+
Console.WriteLine($"Company's greeting: {engine.Evaluate("company.sayHello('Mary')")}");
13+
14+
15+
public class Company
16+
{
17+
public string Field = "public field value";
18+
public string Name => "Jint";
19+
public string SayHello(string name) => $"Hello {name}!";
20+
public int this[int index] => index;
21+
}
22+

Jint.Repl/Jint.Repl.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
<OutputType>Exe</OutputType>
55
<IsPackable>false</IsPackable>
66
<ImplicitUsings>enable</ImplicitUsings>
7+
<PublishAot>true</PublishAot>
78
</PropertyGroup>
89
<ItemGroup>
910
<ProjectReference Include="..\Jint\Jint.csproj" />
11+
<TrimmerRootAssembly Include="Jint" />
1012
</ItemGroup>
1113
</Project>

Jint.Repl/Program.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
using System.Diagnostics;
2-
using System.Reflection;
1+
using System.Reflection;
32
using Esprima;
43
using Jint;
54
using Jint.Native;
65
using Jint.Native.Json;
76
using Jint.Runtime;
87

8+
#pragma warning disable IL2026
9+
#pragma warning disable IL2111
10+
911
var engine = new Engine(cfg => cfg
1012
.AllowClr()
1113
);
@@ -30,8 +32,7 @@
3032
}
3133

3234
var assembly = Assembly.GetExecutingAssembly();
33-
var fvi = FileVersionInfo.GetVersionInfo(assembly.Location);
34-
var version = fvi.FileVersion;
35+
var version = assembly.GetName().Version?.ToString();
3536

3637
Console.WriteLine("Welcome to Jint ({0})", version);
3738
Console.WriteLine("Type 'exit' to leave, " +

Jint.Tests.PublicInterface/Jint.Tests.PublicInterface.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<LangVersion>latest</LangVersion>
1010
<NoWarn>612</NoWarn>
1111
<ImplicitUsings>enable</ImplicitUsings>
12+
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
1213
</PropertyGroup>
1314

1415

Jint.Tests/Runtime/EngineTests.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -602,14 +602,15 @@ public void EvalFunctionParseAndExecuteCode()
602602
[Fact]
603603
public void ForInStatement()
604604
{
605-
RunTest(@"
605+
var engine = new Engine();
606+
var result = engine.Evaluate("""
606607
var x, y, str = '';
607608
for(var z in this) {
608-
str += z;
609+
str += z;
609610
}
610-
611-
equal('xystrz', str);
612-
");
611+
return str;
612+
""");
613+
Assert.Equal("xystrz", result);
613614
}
614615

615616
[Fact]

Jint.Tests/Runtime/InteropTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3431,7 +3431,7 @@ public void ShouldRespectConcreteGenericReturnTypes()
34313431
});
34323432

34333433
var result = new List<string>();
3434-
void Debug(object? o)
3434+
void Debug(object o)
34353435
{
34363436
result.Add($"{o?.GetType().Name ?? "null"}: {o ?? "null"}");
34373437
}

Jint.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
2525
Directory.Build.props = Directory.Build.props
2626
EndProjectSection
2727
EndProject
28+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jint.AotExample", "Jint.AotExample\Jint.AotExample.csproj", "{E07CC7D2-2ADF-4D71-A5B1-88209FFC29CD}"
29+
EndProject
2830
Global
2931
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3032
Debug|Any CPU = Debug|Any CPU
@@ -59,6 +61,10 @@ Global
5961
{70198CE9-7DFE-40CA-BBAC-1454C92C4109}.Debug|Any CPU.Build.0 = Debug|Any CPU
6062
{70198CE9-7DFE-40CA-BBAC-1454C92C4109}.Release|Any CPU.ActiveCfg = Release|Any CPU
6163
{70198CE9-7DFE-40CA-BBAC-1454C92C4109}.Release|Any CPU.Build.0 = Release|Any CPU
64+
{E07CC7D2-2ADF-4D71-A5B1-88209FFC29CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
65+
{E07CC7D2-2ADF-4D71-A5B1-88209FFC29CD}.Debug|Any CPU.Build.0 = Debug|Any CPU
66+
{E07CC7D2-2ADF-4D71-A5B1-88209FFC29CD}.Release|Any CPU.ActiveCfg = Release|Any CPU
67+
{E07CC7D2-2ADF-4D71-A5B1-88209FFC29CD}.Release|Any CPU.Build.0 = Release|Any CPU
6268
EndGlobalSection
6369
GlobalSection(SolutionProperties) = preSolution
6470
HideSolutionNode = FALSE

Jint/Engine.cs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Diagnostics;
2+
using System.Diagnostics.CodeAnalysis;
23
using System.Runtime.CompilerServices;
34
using Esprima;
45
using Esprima.Ast;
@@ -227,7 +228,7 @@ internal ExecutionContext EnterExecutionContext(in ExecutionContext context)
227228
/// </summary>
228229
public Engine SetValue(string name, Delegate value)
229230
{
230-
Realm.GlobalObject.FastSetProperty(name, new PropertyDescriptor(new DelegateWrapper(this, value), true, false, true));
231+
Realm.GlobalObject.FastSetProperty(name, new PropertyDescriptor(new DelegateWrapper(this, value), PropertyFlag.NonEnumerable));
231232
return this;
232233
}
233234

@@ -244,23 +245,23 @@ public Engine SetValue(string name, string? value)
244245
/// </summary>
245246
public Engine SetValue(string name, double value)
246247
{
247-
return SetValue(name, JsNumber.Create(value));
248+
return SetValue(name, (JsValue) JsNumber.Create(value));
248249
}
249250

250251
/// <summary>
251252
/// Registers an integer value as variable.
252253
/// </summary>
253254
public Engine SetValue(string name, int value)
254255
{
255-
return SetValue(name, JsNumber.Create(value));
256+
return SetValue(name, (JsValue) JsNumber.Create(value));
256257
}
257258

258259
/// <summary>
259260
/// Registers a boolean value as variable.
260261
/// </summary>
261262
public Engine SetValue(string name, bool value)
262263
{
263-
return SetValue(name, value ? JsBoolean.True : JsBoolean.False);
264+
return SetValue(name, (JsValue) (value ? JsBoolean.True : JsBoolean.False));
264265
}
265266

266267
/// <summary>
@@ -273,7 +274,7 @@ public Engine SetValue(string name, JsValue value)
273274
}
274275

275276
/// <summary>
276-
/// Registers an object value as variable, creates an interop wrapper when needed..
277+
/// Registers an object value as variable, creates an interop wrapper when needed.
277278
/// </summary>
278279
public Engine SetValue(string name, object? obj)
279280
{
@@ -284,6 +285,26 @@ public Engine SetValue(string name, object? obj)
284285
return SetValue(name, value);
285286
}
286287

288+
/// <summary>
289+
/// Registers an object value as variable, creates an interop wrapper when needed.
290+
/// </summary>
291+
public Engine SetValue(string name, [DynamicallyAccessedMembers(InteropHelper.DefaultDynamicallyAccessedMemberTypes)] Type type)
292+
{
293+
#pragma warning disable IL2111
294+
return SetValue(name, TypeReference.CreateTypeReference(this, type));
295+
#pragma warning restore IL2111
296+
}
297+
298+
/// <summary>
299+
/// Registers an object value as variable, creates an interop wrapper when needed.
300+
/// </summary>
301+
public Engine SetValue<[DynamicallyAccessedMembers(InteropHelper.DefaultDynamicallyAccessedMemberTypes)] T>(string name, T? obj)
302+
{
303+
return obj is Type t
304+
? SetValue(name, t)
305+
: SetValue(name, JsValue.FromObject(this, obj));
306+
}
307+
287308
internal void LeaveExecutionContext()
288309
{
289310
_executionContexts.Pop();

Jint/Extensions/ReflectionExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,21 @@ internal static Type GetDefinedType(this MemberInfo memberInfo)
4141
};
4242
}
4343

44-
internal static IEnumerable<MethodInfo> GetExtensionMethods(this Type type)
44+
internal static IEnumerable<MethodInfo> GetExtensionMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] this Type type)
4545
{
4646
return type.GetMethods(BindingFlags.Public | BindingFlags.Static)
4747
.Where(static m => m.IsExtensionMethod());
4848
}
4949

50-
internal static IEnumerable<MethodInfo> GetOperatorOverloadMethods(this Type type)
50+
internal static IEnumerable<MethodInfo> GetOperatorOverloadMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] this Type type)
5151
{
5252
return type.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
5353
.Where(static m => m.IsSpecialName);
5454
}
5555

5656
private static bool IsExtensionMethod(this MethodBase methodInfo)
5757
{
58-
return methodInfo.IsDefined(typeof(ExtensionAttribute), true);
58+
return methodInfo.IsDefined(typeof(ExtensionAttribute), inherit: true);
5959
}
6060

6161
public static bool IsNullable(this Type type)

Jint/Jint.csproj

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919

2020
<NoWarn>$(NoWarn);1591</NoWarn>
2121

22+
<IsAotCompatible Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)', 'net7.0'))">true</IsAotCompatible>
23+
24+
<PolySharpExcludeGeneratedTypes>System.Runtime.CompilerServices.IsExternalInit;System.Runtime.CompilerServices.RequiresLocationAttribute</PolySharpExcludeGeneratedTypes>
25+
<PolySharpIncludeRuntimeSupportedAttributes>true</PolySharpIncludeRuntimeSupportedAttributes>
26+
2227
</PropertyGroup>
2328

2429
<PropertyGroup Condition=" '$(TargetFramework)' != 'net462' and '$(TargetFramework)' != 'netstandard2.0' ">

Jint/Native/ShadowRealm/ShadowRealm.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Esprima;
1+
using System.Diagnostics.CodeAnalysis;
2+
using Esprima;
23
using Esprima.Ast;
34
using Esprima.Utils;
45
using Jint.Native.Object;
@@ -55,9 +56,11 @@ public JsValue ImportValue(string specifier, string exportName)
5556
_engine.RunAvailableContinuations();
5657
return value;
5758
}
59+
60+
[RequiresUnreferencedCode("User supplied delegate")]
5861
public ShadowRealm SetValue(string name, Delegate value)
5962
{
60-
_shadowRealm.GlobalObject.FastSetProperty(name, new PropertyDescriptor(new DelegateWrapper(_engine, value), true, false, true));
63+
_shadowRealm.GlobalObject.FastSetProperty(name, new PropertyDescriptor(new DelegateWrapper(_engine, value), PropertyFlag.NonEnumerable));
6164
return this;
6265
}
6366

Jint/Options.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,20 @@ internal void Apply(Engine engine)
114114
// add missing bits if needed
115115
if (Interop.Enabled)
116116
{
117-
engine.Realm.GlobalObject.SetProperty("System",
118-
new PropertyDescriptor(new NamespaceReference(engine, "System"), PropertyFlag.AllForbidden));
117+
#pragma warning disable IL2026
118+
119+
engine.Realm.GlobalObject.SetProperty("System", new PropertyDescriptor(new NamespaceReference(engine, "System"), PropertyFlag.AllForbidden));
120+
119121
engine.Realm.GlobalObject.SetProperty("importNamespace", new PropertyDescriptor(new ClrFunction(
120122
engine,
121123
"importNamespace",
122124
(thisObj, arguments) =>
123125
new NamespaceReference(engine, TypeConverter.ToString(arguments.At(0)))),
124126
PropertyFlag.AllForbidden));
125-
engine.Realm.GlobalObject.SetProperty("clrHelper", new PropertyDescriptor(
126-
new ObjectWrapper(engine, new ClrHelper(Interop)),
127-
PropertyFlag.AllForbidden));
127+
128+
engine.Realm.GlobalObject.SetProperty("clrHelper", new PropertyDescriptor(new ObjectWrapper(engine, new ClrHelper(Interop)), PropertyFlag.AllForbidden));
129+
130+
#pragma warning restore IL2026
128131
}
129132

130133
if (Interop.ExtensionMethodTypes.Count > 0)

Jint/Runtime/InternalTypes.cs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
namespace Jint.Runtime;
2+
3+
[Flags]
4+
internal enum InternalTypes
5+
{
6+
// should not be used, used for empty match
7+
Empty = 0,
8+
9+
Undefined = 1,
10+
Null = 2,
11+
12+
// primitive types range start
13+
Boolean = 4,
14+
String = 8,
15+
Number = 16,
16+
Integer = 32,
17+
Symbol = 64,
18+
BigInt = 128,
19+
20+
// primitive types range end
21+
Object = 256,
22+
23+
PrivateName = 512,
24+
25+
// internal usage
26+
ObjectEnvironmentRecord = 1024,
27+
RequiresCloning = 2048,
28+
Module = 4096,
29+
30+
// the object doesn't override important GetOwnProperty etc which change behavior
31+
PlainObject = 8192,
32+
// our native array
33+
Array = 16384,
34+
35+
Primitive = Boolean | String | Number | Integer | BigInt | Symbol,
36+
InternalFlags = ObjectEnvironmentRecord | RequiresCloning | PlainObject | Array | Module
37+
}

Jint/Runtime/Interop/ClrHelper.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
namespace Jint.Runtime.Interop;
1+
using Jint.Native;
22

3-
using Jint.Native;
3+
namespace Jint.Runtime.Interop;
44

5-
public class ClrHelper
5+
#pragma warning disable IL2072
6+
7+
internal sealed class ClrHelper
68
{
79
private readonly Options.InteropOptions _interopOptions;
810

@@ -74,10 +76,8 @@ public JsValue ObjectToType(ObjectWrapper obj)
7476
{
7577
return TypeReference.CreateTypeReference(obj.Engine, t);
7678
}
77-
else
78-
{
79-
ExceptionHelper.ThrowArgumentException("Must be an ObjectWrapper of Type", nameof(obj));
80-
}
79+
80+
ExceptionHelper.ThrowArgumentException("Must be an ObjectWrapper of Type", nameof(obj));
8181
return JsValue.Undefined;
8282
}
8383

0 commit comments

Comments
 (0)