Skip to content

Commit 70a9c6f

Browse files
Version 7.2.5: Added V8Runtime.HeapSizeViolationPolicy and V8ScriptEngine.RuntimeHeapSizeViolationPolicy (GitHub Issue #369); added ScriptEngine.VoidResultValue and made VoidResult.Value public (GitHub Issue #372); fixed array buffer memory leak (GitHub Issue #370); fixed access to events with inaccessible handler types (GitHub Issue #365); updated API documentation. Tested with V8 10.1.124.11.
1 parent 9000508 commit 70a9c6f

File tree

697 files changed

+2699
-1151
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

697 files changed

+2699
-1151
lines changed

ClearScript/Exports/VersionSymbols.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
#pragma once
77

8-
#define CLEARSCRIPT_VERSION_STRING "7.2.4"
9-
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 7,2,4
10-
#define CLEARSCRIPT_VERSION_STRING_INFORMATIONAL "7.2.4"
8+
#define CLEARSCRIPT_VERSION_STRING "7.2.5"
9+
#define CLEARSCRIPT_VERSION_COMMA_SEPARATED 7,2,5
10+
#define CLEARSCRIPT_VERSION_STRING_INFORMATIONAL "7.2.5"
1111
#define CLEARSCRIPT_FILE_FLAGS 0L

ClearScript/HostEvent.cs

+79-33
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,24 @@
88
namespace Microsoft.ClearScript
99
{
1010
/// <summary>
11-
/// Represents a host event source.
11+
/// Provides the base implementation for a host event source.
1212
/// </summary>
13-
/// <typeparam name="T">The event handler delegate type.</typeparam>
14-
public class EventSource<T>
13+
public abstract class EventSource
1514
{
16-
private readonly ScriptEngine engine;
17-
1815
internal EventSource(ScriptEngine engine, object source, EventInfo eventInfo)
1916
{
2017
MiscHelpers.VerifyNonNullArgument(engine, nameof(engine));
2118
MiscHelpers.VerifyNonNullArgument(eventInfo, nameof(eventInfo));
2219

23-
if (eventInfo.EventHandlerType != typeof(T))
24-
{
25-
throw new ArgumentException("Invalid event type", nameof(eventInfo));
26-
}
27-
28-
this.engine = engine;
20+
Engine = engine;
2921
Source = source;
3022
EventInfo = eventInfo;
3123
}
3224

25+
internal ScriptEngine Engine { get; }
26+
27+
internal abstract Type HandlerType { get; }
28+
3329
internal object Source { get; }
3430

3531
internal EventInfo EventInfo { get; }
@@ -42,33 +38,68 @@ internal EventSource(ScriptEngine engine, object source, EventInfo eventInfo)
4238
/// Connects the host event source to the specified script handler function.
4339
/// </summary>
4440
/// <param name="scriptFunc">The script function that will handle the event.</param>
45-
/// <returns>An <see cref="EventConnection{T}"/> that represents the connection.</returns>
46-
public EventConnection<T> connect(object scriptFunc)
41+
/// <returns>An <see cref="EventConnection"/> that represents the connection.</returns>
42+
public EventConnection connect(object scriptFunc)
4743
{
4844
MiscHelpers.VerifyNonNullArgument(scriptFunc, nameof(scriptFunc));
49-
return engine.CreateEventConnection<T>(Source, EventInfo, DelegateFactory.CreateDelegate(engine, scriptFunc, typeof(T)));
45+
return Engine.CreateEventConnection(HandlerType, Source, EventInfo, DelegateFactory.CreateDelegate(Engine, scriptFunc, HandlerType));
5046
}
5147

5248
// ReSharper restore InconsistentNaming
5349

5450
#endregion
5551
}
5652

57-
internal interface IEventConnection
53+
/// <summary>
54+
/// Represents a host event source.
55+
/// </summary>
56+
/// <typeparam name="T">The event handler delegate type.</typeparam>
57+
public sealed class EventSource<T> : EventSource
5858
{
59-
void Break();
59+
internal EventSource(ScriptEngine engine, object source, EventInfo eventInfo)
60+
: base(engine, source, eventInfo)
61+
{
62+
if (eventInfo.EventHandlerType != typeof(T))
63+
{
64+
throw new ArgumentException("Invalid event type (handler type mismatch)", nameof(eventInfo));
65+
}
66+
}
67+
68+
#region EventSource overrides
69+
70+
internal override Type HandlerType => typeof(T);
71+
72+
#endregion
73+
74+
#region script-callable interface
75+
76+
// ReSharper disable InconsistentNaming
77+
78+
/// <summary>
79+
/// Connects the host event source to the specified script handler function.
80+
/// </summary>
81+
/// <param name="scriptFunc">The script function that will handle the event.</param>
82+
/// <returns>An <see cref="EventConnection{T}"/> that represents the connection.</returns>
83+
public new EventConnection<T> connect(object scriptFunc)
84+
{
85+
MiscHelpers.VerifyNonNullArgument(scriptFunc, nameof(scriptFunc));
86+
return Engine.CreateEventConnection<T>(Source, EventInfo, DelegateFactory.CreateDelegate(Engine, scriptFunc, typeof(T)));
87+
}
88+
89+
// ReSharper restore InconsistentNaming
90+
91+
#endregion
6092
}
6193

6294
/// <summary>
63-
/// Represents a connection between a host event source and a script handler function.
95+
/// Provides the base implementation for a connection between a host event source and a script handler function.
6496
/// </summary>
65-
/// <typeparam name="T">The event handler delegate type.</typeparam>
66-
public class EventConnection<T> : IEventConnection
97+
public abstract class EventConnection
6798
{
6899
private readonly ScriptEngine engine;
69100
private readonly object source;
70-
private readonly EventInfo eventInfo;
71-
private readonly Delegate handler;
101+
private readonly MethodInfo removeMethod;
102+
private readonly object[] parameters;
72103
private readonly InterlockedOneWayFlag brokenFlag = new InterlockedOneWayFlag();
73104

74105
internal EventConnection(ScriptEngine engine, object source, EventInfo eventInfo, Delegate handler)
@@ -77,17 +108,28 @@ internal EventConnection(ScriptEngine engine, object source, EventInfo eventInfo
77108
MiscHelpers.VerifyNonNullArgument(handler, nameof(handler));
78109
MiscHelpers.VerifyNonNullArgument(eventInfo, nameof(eventInfo));
79110

80-
if (eventInfo.EventHandlerType != typeof(T))
111+
if (!MiscHelpers.Try(out var addMethod, () => eventInfo.GetAddMethod(true)) || (addMethod == null))
81112
{
82-
throw new ArgumentException("Invalid event type", nameof(eventInfo));
113+
throw new ArgumentException("Invalid event type (no accessible add method)", nameof(eventInfo));
114+
}
115+
116+
if (!MiscHelpers.Try(out removeMethod, () => eventInfo.GetRemoveMethod(true)) || (removeMethod == null))
117+
{
118+
throw new ArgumentException("Invalid event type (no accessible remove method)", nameof(eventInfo));
83119
}
84120

85121
this.engine = engine;
86122
this.source = source;
87-
this.eventInfo = eventInfo;
88-
this.handler = handler;
89123

90-
eventInfo.AddEventHandler(source, handler);
124+
addMethod.Invoke(source, parameters = new object[] { handler });
125+
}
126+
127+
internal void Break()
128+
{
129+
if (brokenFlag.Set())
130+
{
131+
removeMethod.Invoke(source, parameters);
132+
}
91133
}
92134

93135
#region script-callable interface
@@ -105,17 +147,21 @@ public void disconnect()
105147
// ReSharper restore InconsistentNaming
106148

107149
#endregion
150+
}
108151

109-
#region IEventConnection implementation
110-
111-
void IEventConnection.Break()
152+
/// <summary>
153+
/// Represents a connection between a host event source and a script handler function.
154+
/// </summary>
155+
/// <typeparam name="T">The event handler delegate type.</typeparam>
156+
public sealed class EventConnection<T> : EventConnection
157+
{
158+
internal EventConnection(ScriptEngine engine, object source, EventInfo eventInfo, Delegate handler)
159+
: base(engine, source, eventInfo, handler)
112160
{
113-
if (brokenFlag.Set())
161+
if (eventInfo.EventHandlerType != typeof(T))
114162
{
115-
eventInfo.RemoveEventHandler(source, handler);
163+
throw new ArgumentException("Invalid event type (handler type mismatch)", nameof(eventInfo));
116164
}
117165
}
118-
119-
#endregion
120166
}
121167
}

ClearScript/HostItem.InvokeMethod.cs

+10-6
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ private MethodBindResult BindMethod(string name, Type[] typeArgs, object[] args,
117117
}
118118
else
119119
{
120-
result = BindMethodInternal(AccessContext, bindFlags, Target, name, typeArgs, args, bindArgs);
120+
result = BindMethodInternal(signature, AccessContext, bindFlags, Target, name, typeArgs, args, bindArgs);
121121
if (!result.IsPreferredMethod(this, name))
122122
{
123123
if (result is MethodBindSuccess)
@@ -127,7 +127,7 @@ private MethodBindResult BindMethod(string name, Type[] typeArgs, object[] args,
127127

128128
foreach (var altName in GetAltMethodNames(name, bindFlags))
129129
{
130-
var altResult = BindMethodInternal(AccessContext, bindFlags, Target, altName, typeArgs, args, bindArgs);
130+
var altResult = BindMethodInternal(null, AccessContext, bindFlags, Target, altName, typeArgs, args, bindArgs);
131131
if (altResult.IsUnblockedMethod(this))
132132
{
133133
result = altResult;
@@ -151,12 +151,16 @@ private MethodBindResult BindMethod(string name, Type[] typeArgs, object[] args,
151151
return result;
152152
}
153153

154-
private static MethodBindResult BindMethodInternal(Type bindContext, BindingFlags bindFlags, HostTarget target, string name, Type[] typeArgs, object[] args, object[] bindArgs)
154+
private static MethodBindResult BindMethodInternal(BindSignature signature, Type bindContext, BindingFlags bindFlags, HostTarget target, string name, Type[] typeArgs, object[] args, object[] bindArgs)
155155
{
156-
// WARNING: BindSignature holds on to the specified typeArgs; subsequent modification
157-
// will result in bugs that are difficult to diagnose. Create a copy if necessary.
156+
if (signature == null)
157+
{
158+
// WARNING: BindSignature holds on to the specified typeArgs; subsequent modification
159+
// will result in bugs that are difficult to diagnose. Create a copy if necessary.
160+
161+
signature = new BindSignature(bindContext, bindFlags, target, name, typeArgs, bindArgs);
162+
}
158163

159-
var signature = new BindSignature(bindContext, bindFlags, target, name, typeArgs, bindArgs);
160164
MethodBindResult result;
161165

162166
if (coreBindCache.TryGetValue(signature, out var rawResult))

ClearScript/HostItem.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1479,9 +1479,8 @@ private object GetHostProperty(string name, BindingFlags invokeFlags, object[] a
14791479
var eventInfo = Target.Type.GetScriptableEvent(name, invokeFlags, AccessContext, DefaultAccess);
14801480
if (eventInfo != null)
14811481
{
1482-
var type = typeof(EventSource<>).MakeSpecificType(eventInfo.EventHandlerType);
14831482
isCacheable = (TargetDynamicMetaObject == null);
1484-
return type.CreateInstance(BindingFlags.NonPublic, Engine, Target.InvokeTarget, eventInfo);
1483+
return typeof(EventSource<>).MakeSpecificType(eventInfo.EventHandlerType).CreateInstance(BindingFlags.NonPublic, Engine, Target.InvokeTarget, eventInfo);
14851484
}
14861485

14871486
var field = Target.Type.GetScriptableField(name, invokeFlags, AccessContext, DefaultAccess);

ClearScript/Properties/AssemblyInfo.Core.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,15 @@
1818
[assembly: InternalsVisibleTo("ClearScriptTest")]
1919

2020
[assembly: ComVisible(false)]
21-
[assembly: AssemblyVersion("7.2.4")]
22-
[assembly: AssemblyFileVersion("7.2.4")]
23-
[assembly: AssemblyInformationalVersion("7.2.4")]
21+
[assembly: AssemblyVersion("7.2.5")]
22+
[assembly: AssemblyFileVersion("7.2.5")]
23+
[assembly: AssemblyInformationalVersion("7.2.5")]
2424

2525
namespace Microsoft.ClearScript.Properties
2626
{
2727
internal static class ClearScriptVersion
2828
{
29-
public const string Triad = "7.2.4";
30-
public const string Informational = "7.2.4";
29+
public const string Triad = "7.2.5";
30+
public const string Informational = "7.2.5";
3131
}
3232
}

ClearScript/Properties/AssemblyInfo.V8.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515
[assembly: InternalsVisibleTo("ClearScriptTest")]
1616

1717
[assembly: ComVisible(false)]
18-
[assembly: AssemblyVersion("7.2.4")]
19-
[assembly: AssemblyFileVersion("7.2.4")]
20-
[assembly: AssemblyInformationalVersion("7.2.4")]
18+
[assembly: AssemblyVersion("7.2.5")]
19+
[assembly: AssemblyFileVersion("7.2.5")]
20+
[assembly: AssemblyInformationalVersion("7.2.5")]

ClearScript/Properties/AssemblyInfo.Windows.Core.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
[assembly: InternalsVisibleTo("ClearScriptTest")]
1717

1818
[assembly: ComVisible(false)]
19-
[assembly: AssemblyVersion("7.2.4")]
20-
[assembly: AssemblyFileVersion("7.2.4")]
21-
[assembly: AssemblyInformationalVersion("7.2.4")]
19+
[assembly: AssemblyVersion("7.2.5")]
20+
[assembly: AssemblyFileVersion("7.2.5")]
21+
[assembly: AssemblyInformationalVersion("7.2.5")]

ClearScript/Properties/AssemblyInfo.Windows.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@
1515
[assembly: InternalsVisibleTo("ClearScriptTest")]
1616

1717
[assembly: ComVisible(false)]
18-
[assembly: AssemblyVersion("7.2.4")]
19-
[assembly: AssemblyFileVersion("7.2.4")]
20-
[assembly: AssemblyInformationalVersion("7.2.4")]
18+
[assembly: AssemblyVersion("7.2.5")]
19+
[assembly: AssemblyFileVersion("7.2.5")]
20+
[assembly: AssemblyInformationalVersion("7.2.5")]

ClearScript/ScriptEngine.cs

+34-6
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,19 @@ public bool DisableExtensionMethods
296296
/// </remarks>
297297
public object UndefinedImportValue { get; set; } = Undefined.Value;
298298

299+
/// <summary>
300+
/// Gets or sets the engine's void result export value.
301+
/// </summary>
302+
/// <remarks>
303+
/// Some script languages expect every subroutine call to return a value. When script code
304+
/// written in such a language invokes a host method that explicitly returns no value (such
305+
/// as a C#
306+
/// <see href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/void">void</see>
307+
/// method), the script engine returns the value of this property as a dummy result. The
308+
/// default value is <see cref="VoidResult.Value"/>.
309+
/// </remarks>
310+
public object VoidResultValue { get; set; } = VoidResult.Value;
311+
299312
/// <summary>
300313
/// Gets or sets a callback that can be used to halt script execution.
301314
/// </summary>
@@ -1947,12 +1960,17 @@ internal HostTargetMemberData GetSharedHostObjectMemberData(HostObject target, T
19471960

19481961
private readonly EventConnectionMap eventConnectionMap = new EventConnectionMap();
19491962

1963+
internal EventConnection CreateEventConnection(Type handlerType, object source, EventInfo eventInfo, Delegate handler)
1964+
{
1965+
return eventConnectionMap.Create(this, handlerType, source, eventInfo, handler);
1966+
}
1967+
19501968
internal EventConnection<T> CreateEventConnection<T>(object source, EventInfo eventInfo, Delegate handler)
19511969
{
19521970
return eventConnectionMap.Create<T>(this, source, eventInfo, handler);
19531971
}
19541972

1955-
internal void BreakEventConnection(IEventConnection connection)
1973+
internal void BreakEventConnection(EventConnection connection)
19561974
{
19571975
eventConnectionMap.Break(connection);
19581976
}
@@ -2035,25 +2053,35 @@ internal sealed class ScriptFrame
20352053

20362054
private sealed class EventConnectionMap : IDisposable
20372055
{
2038-
private readonly HashSet<IEventConnection> map = new HashSet<IEventConnection>();
2056+
private readonly HashSet<EventConnection> map = new HashSet<EventConnection>();
20392057
private readonly InterlockedOneWayFlag disposedFlag = new InterlockedOneWayFlag();
20402058

2059+
internal EventConnection Create(ScriptEngine engine, Type handlerType, object source, EventInfo eventInfo, Delegate handler)
2060+
{
2061+
var connection = (EventConnection)typeof(EventConnection<>).MakeGenericType(handlerType).CreateInstance(BindingFlags.NonPublic, engine, source, eventInfo, handler);
2062+
Add(connection);
2063+
return connection;
2064+
}
2065+
20412066
internal EventConnection<T> Create<T>(ScriptEngine engine, object source, EventInfo eventInfo, Delegate handler)
20422067
{
20432068
var connection = new EventConnection<T>(engine, source, eventInfo, handler);
2069+
Add(connection);
2070+
return connection;
2071+
}
20442072

2073+
private void Add(EventConnection connection)
2074+
{
20452075
if (!disposedFlag.IsSet)
20462076
{
20472077
lock (map)
20482078
{
20492079
map.Add(connection);
20502080
}
20512081
}
2052-
2053-
return connection;
20542082
}
20552083

2056-
internal void Break(IEventConnection connection)
2084+
internal void Break(EventConnection connection)
20572085
{
20582086
var mustBreak = true;
20592087

@@ -2075,7 +2103,7 @@ public void Dispose()
20752103
{
20762104
if (disposedFlag.Set())
20772105
{
2078-
var connections = new List<IEventConnection>();
2106+
var connections = new List<EventConnection>();
20792107

20802108
lock (map)
20812109
{

ClearScript/Undefined.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ namespace Microsoft.ClearScript
99
/// <remarks>
1010
/// Some script languages support one or more special non-<c>null</c> values that represent
1111
/// nonexistent, missing, unknown, or undefined data. The ClearScript library maps such values
12-
/// to instances of this class.
12+
/// to an instance of this class.
1313
/// </remarks>
14+
/// <seealso cref="ScriptEngine.UndefinedImportValue"/>
1415
public class Undefined
1516
{
1617
/// <summary>

0 commit comments

Comments
 (0)