Skip to content

Commit 0deec16

Browse files
committed
In JavaScript engine settings was added one new property - AllowReflection (default false)
1 parent a61ba63 commit 0deec16

38 files changed

+696
-148
lines changed

build-js.cmd

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
@echo off
2+
setlocal
3+
4+
cd ./src/MsieJavaScriptEngine/
5+
6+
::--------------------------------------------------------------------------------
7+
:: Build
8+
::--------------------------------------------------------------------------------
9+
10+
echo Installing Node.js packages ...
11+
echo.
12+
call npm install
13+
if errorlevel 1 goto error
14+
echo.
15+
16+
echo Minifying JS files ...
17+
echo.
18+
call npm run -s minify-js
19+
if errorlevel 1 goto error
20+
echo.
21+
22+
::--------------------------------------------------------------------------------
23+
:: Exit
24+
::--------------------------------------------------------------------------------
25+
26+
echo Succeeded!
27+
goto exit
28+
29+
:error
30+
echo *** Error: The previous step failed!
31+
32+
:exit
33+
cd ../../
34+
endlocal

global.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"sdk": {
3-
"version": "7.0.102"
3+
"version": "7.0.200"
44
}
55
}

src/MsieJavaScriptEngine/.uglifyjsrc

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"compress": {
3+
"hoist_funs": true,
4+
"hoist_vars": true,
5+
"passes": 2
6+
},
7+
"mangle": {},
8+
"output": {
9+
"comments": "/^!/"
10+
}
11+
}

src/MsieJavaScriptEngine/ActiveScript/ActiveScriptJsEngineBase.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ private void InnerCollectGarbage(ScriptGCType type)
571571
/// <returns>The mapped value</returns>
572572
private object MapToScriptType(object value)
573573
{
574-
return TypeMappingHelpers.MapToScriptType(value, _settings.EngineMode);
574+
return TypeMappingHelpers.MapToScriptType(value, _settings.EngineMode, _settings.AllowReflection);
575575
}
576576

577577
/// <summary>
@@ -581,7 +581,7 @@ private object MapToScriptType(object value)
581581
/// <returns>The mapped array</returns>
582582
private object[] MapToScriptType(object[] args)
583583
{
584-
return TypeMappingHelpers.MapToScriptType(args, _settings.EngineMode);
584+
return TypeMappingHelpers.MapToScriptType(args, _settings.EngineMode, _settings.AllowReflection);
585585
}
586586

587587
/// <summary>
@@ -900,7 +900,7 @@ public override void EmbedHostObject(string itemName, object value)
900900

901901
public override void EmbedHostType(string itemName, Type type)
902902
{
903-
var typeValue = new HostType(type, _settings.EngineMode);
903+
var typeValue = new HostType(type, _settings.EngineMode, _settings.AllowReflection);
904904

905905
_dispatcher.Invoke(() =>
906906
{

src/MsieJavaScriptEngine/ActiveScript/HostItemBase.cs

+57-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ internal abstract class HostItemBase : IReflect
2727
/// </summary>
2828
protected readonly JsEngineMode _engineMode;
2929

30+
/// <summary>
31+
/// Flag for whether to allow the usage of reflection API in the script code
32+
/// </summary>
33+
protected readonly bool _allowReflection;
34+
3035
/// <summary>
3136
/// List of fields
3237
/// </summary>
@@ -57,20 +62,26 @@ public object Target
5762
/// <param name="type">Target type</param>
5863
/// <param name="target">Target object</param>
5964
/// <param name="engineMode">JS engine mode</param>
65+
/// <param name="allowReflection">Flag for whether to allow the usage of reflection API in the script code</param>
6066
/// <param name="instance">Flag for whether to allow access to members of the instance</param>
61-
protected HostItemBase(Type type, object target, JsEngineMode engineMode, bool instance)
67+
protected HostItemBase(Type type, object target, JsEngineMode engineMode, bool allowReflection, bool instance)
6268
{
6369
_type = type;
6470
_target = target;
71+
_allowReflection = allowReflection;
6572
_engineMode = engineMode;
6673

6774
BindingFlags defaultBindingFlags = ReflectionHelpers.GetDefaultBindingFlags(instance);
6875
FieldInfo[] fields = _type.GetFields(defaultBindingFlags);
6976
PropertyInfo[] properties = _type.GetProperties(defaultBindingFlags);
77+
if (properties.Length > 0 && !allowReflection)
78+
{
79+
properties = GetAvailableProperties(properties);
80+
}
7081
MethodInfo[] methods = _type.GetMethods(defaultBindingFlags);
71-
if (methods.Length > 0 && properties.Length > 0)
82+
if (methods.Length > 0 && (properties.Length > 0 || !allowReflection))
7283
{
73-
methods = ReflectionHelpers.GetFullyFledgedMethods(methods);
84+
methods = GetAvailableMethods(methods, allowReflection);
7485
}
7586

7687
_fields = fields;
@@ -79,6 +90,49 @@ protected HostItemBase(Type type, object target, JsEngineMode engineMode, bool i
7990
}
8091

8192

93+
private static PropertyInfo[] GetAvailableProperties(PropertyInfo[] properties)
94+
{
95+
int propertyCount = properties.Length;
96+
var availableProperties = new PropertyInfo[propertyCount];
97+
int availablePropertyIndex = 0;
98+
99+
for (int propertyIndex = 0; propertyIndex < propertyCount; propertyIndex++)
100+
{
101+
PropertyInfo property = properties[propertyIndex];
102+
if (ReflectionHelpers.IsAllowedProperty(property))
103+
{
104+
availableProperties[availablePropertyIndex] = property;
105+
availablePropertyIndex++;
106+
}
107+
}
108+
109+
Array.Resize(ref availableProperties, availablePropertyIndex);
110+
111+
return availableProperties;
112+
}
113+
114+
private static MethodInfo[] GetAvailableMethods(MethodInfo[] methods, bool allowReflection)
115+
{
116+
int methodCount = methods.Length;
117+
var availableMethods = new MethodInfo[methodCount];
118+
int availableMethodIndex = 0;
119+
120+
for (int methodIndex = 0; methodIndex < methodCount; methodIndex++)
121+
{
122+
MethodInfo method = methods[methodIndex];
123+
if (ReflectionHelpers.IsFullyFledgedMethod(method)
124+
&& (allowReflection || ReflectionHelpers.IsAllowedMethod(method)))
125+
{
126+
availableMethods[availableMethodIndex] = method;
127+
availableMethodIndex++;
128+
}
129+
}
130+
131+
Array.Resize(ref availableMethods, availableMethodIndex);
132+
133+
return availableMethods;
134+
}
135+
82136
private bool IsField(string name)
83137
{
84138
bool isField = false;

src/MsieJavaScriptEngine/ActiveScript/HostObject.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ internal sealed class HostObject : HostItemBase
2525
/// </summary>
2626
/// <param name="target">Target object</param>
2727
/// <param name="engineMode">JS engine mode</param>
28-
public HostObject(object target, JsEngineMode engineMode)
29-
: base(target.GetType(), target, engineMode, true)
28+
/// <param name="allowReflection">Flag for whether to allow the usage of reflection API in the script code</param>
29+
public HostObject(object target, JsEngineMode engineMode, bool allowReflection)
30+
: base(target.GetType(), target, engineMode, allowReflection, true)
3031
{
3132
var del = _target as Delegate;
3233
if (del != null)
@@ -88,7 +89,7 @@ protected override object InnerInvokeMember(string name, BindingFlags invokeAttr
8889
processedArgs, modifiers, culture, namedParameters);
8990
}
9091

91-
return TypeMappingHelpers.MapToScriptType(result, _engineMode);
92+
return TypeMappingHelpers.MapToScriptType(result, _engineMode, _allowReflection);
9293
}
9394

9495
#endregion

src/MsieJavaScriptEngine/ActiveScript/HostType.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ internal sealed class HostType : HostItemBase
1919
/// </summary>
2020
/// <param name="type">Target type</param>
2121
/// <param name="engineMode">JS engine mode</param>
22-
public HostType(Type type, JsEngineMode engineMode)
23-
: base(type, null, engineMode, false)
22+
/// <param name="allowReflection">Flag for whether to allow the usage of reflection API in the script code</param>
23+
public HostType(Type type, JsEngineMode engineMode, bool allowReflection)
24+
: base(type, null, engineMode, allowReflection, false)
2425
{ }
2526

2627

@@ -51,7 +52,7 @@ protected override object InnerInvokeMember(string name, BindingFlags invokeAttr
5152
processedArgs, modifiers, culture, namedParameters);
5253
}
5354

54-
return TypeMappingHelpers.MapToScriptType(result, _engineMode);
55+
return TypeMappingHelpers.MapToScriptType(result, _engineMode, _allowReflection);
5556
}
5657

5758
#endregion

src/MsieJavaScriptEngine/Helpers/ReflectionHelpers.cs

+59-23
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,19 @@ namespace MsieJavaScriptEngine.Helpers
1212
/// </summary>
1313
internal static class ReflectionHelpers
1414
{
15+
private static readonly PropertyInfo[] _disallowedProperties =
16+
{
17+
typeof(Delegate).GetProperty("Method"),
18+
typeof(Exception).GetProperty("TargetSite")
19+
};
20+
21+
private static readonly MethodInfo[] _disallowedMethods =
22+
{
23+
typeof(object).GetMethod("GetType"),
24+
typeof(Exception).GetMethod("GetType")
25+
};
26+
27+
1528
public static BindingFlags GetDefaultBindingFlags(bool instance)
1629
{
1730
BindingFlags bindingFlags = BindingFlags.Public;
@@ -27,6 +40,20 @@ public static BindingFlags GetDefaultBindingFlags(bool instance)
2740
return bindingFlags;
2841
}
2942

43+
public static bool IsAllowedProperty(PropertyInfo property)
44+
{
45+
bool isAllowed = !_disallowedProperties.Contains(property, MemberComparer<PropertyInfo>.Instance);
46+
47+
return isAllowed;
48+
}
49+
50+
public static bool IsAllowedMethod(MethodInfo method)
51+
{
52+
bool isAllowed = !_disallowedMethods.Contains(method, MemberComparer<MethodInfo>.Instance);
53+
54+
return isAllowed;
55+
}
56+
3057
public static bool IsFullyFledgedMethod(MethodInfo method)
3158
{
3259
if (!method.Attributes.HasFlag(MethodAttributes.SpecialName))
@@ -40,29 +67,6 @@ public static bool IsFullyFledgedMethod(MethodInfo method)
4067

4168
return isFullyFledged;
4269
}
43-
#if NETFRAMEWORK
44-
45-
public static MethodInfo[] GetFullyFledgedMethods(MethodInfo[] methods)
46-
{
47-
int methodCount = methods.Length;
48-
var fullyFledgedMethods = new MethodInfo[methodCount];
49-
int fullyFledgedMethodIndex = 0;
50-
51-
for (int methodIndex = 0; methodIndex < methodCount; methodIndex++)
52-
{
53-
MethodInfo method = methods[methodIndex];
54-
if (IsFullyFledgedMethod(method))
55-
{
56-
fullyFledgedMethods[fullyFledgedMethodIndex] = method;
57-
fullyFledgedMethodIndex++;
58-
}
59-
}
60-
61-
Array.Resize(ref fullyFledgedMethods, fullyFledgedMethodIndex);
62-
63-
return fullyFledgedMethods;
64-
}
65-
#endif
6670

6771
public static void FixFieldValueType(ref object value, FieldInfo field)
6872
{
@@ -244,6 +248,38 @@ private static bool CompareParameterTypes(object[] argValues, Type[] argTypes, T
244248
}
245249

246250

251+
private sealed class MemberComparer<T> : EqualityComparer<T>
252+
where T : MemberInfo
253+
{
254+
public static MemberComparer<T> Instance { get; } = new MemberComparer<T>();
255+
256+
257+
private MemberComparer()
258+
{ }
259+
260+
261+
#region MemberComparer overrides
262+
263+
public override bool Equals(T x, T y)
264+
{
265+
return x.Module == y.Module
266+
#if !NETSTANDARD1_3
267+
&& x.MetadataToken == y.MetadataToken
268+
#else
269+
&& x.DeclaringType == y.DeclaringType
270+
&& x.Name == y.Name
271+
#endif
272+
;
273+
}
274+
275+
public override int GetHashCode(T obj)
276+
{
277+
return obj != null ? obj.GetHashCode() : 0;
278+
}
279+
280+
#endregion
281+
}
282+
247283
private sealed class MethodWithMetadata
248284
{
249285
public MethodBase Method

src/MsieJavaScriptEngine/Helpers/TypeMappingHelpers.cs

+6-4
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ internal static class TypeMappingHelpers
1717
/// </summary>
1818
/// <param name="value">The source value</param>
1919
/// <param name="engineMode">JavaScript engine mode</param>
20+
/// <param name="allowReflection">Flag for whether to allow the usage of reflection API in the script code</param>
2021
/// <returns>The mapped value</returns>
21-
public static object MapToScriptType(object value, JsEngineMode engineMode)
22+
public static object MapToScriptType(object value, JsEngineMode engineMode, bool allowReflection)
2223
{
2324
if (value == null)
2425
{
@@ -36,7 +37,7 @@ public static object MapToScriptType(object value, JsEngineMode engineMode)
3637
return value;
3738
}
3839

39-
var result = new HostObject(value, engineMode);
40+
var result = new HostObject(value, engineMode, allowReflection);
4041

4142
return result;
4243
}
@@ -46,10 +47,11 @@ public static object MapToScriptType(object value, JsEngineMode engineMode)
4647
/// </summary>
4748
/// <param name="args">The source array</param>
4849
/// <param name="engineMode">JavaScript engine mode</param>
50+
/// <param name="allowReflection">Flag for whether to allow the usage of reflection API in the script code</param>
4951
/// <returns>The mapped array</returns>
50-
public static object[] MapToScriptType(object[] args, JsEngineMode engineMode)
52+
public static object[] MapToScriptType(object[] args, JsEngineMode engineMode, bool allowReflection)
5153
{
52-
return args.Select(arg => MapToScriptType(arg, engineMode)).ToArray();
54+
return args.Select(arg => MapToScriptType(arg, engineMode, allowReflection)).ToArray();
5355
}
5456

5557
/// <summary>

src/MsieJavaScriptEngine/JsEngineSettings.cs

+14
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ public sealed class JsEngineSettings
2727
private int _maxStackSize;
2828

2929
#endif
30+
/// <summary>
31+
/// Gets or sets a flag for whether to allow the usage of reflection API in the script code
32+
/// </summary>
33+
/// <remarks>
34+
/// This affects <see cref="Object.GetType"/>, <c>Exception.GetType</c>,
35+
/// <c>Exception.TargetSite</c> and <c>Delegate.Method</c>.
36+
/// </remarks>
37+
public bool AllowReflection
38+
{
39+
get;
40+
set;
41+
}
42+
3043
/// <summary>
3144
/// Gets or sets a flag for whether to enable script debugging features
3245
/// </summary>
@@ -95,6 +108,7 @@ public bool UseJson2Library
95108
/// </summary>
96109
public JsEngineSettings()
97110
{
111+
AllowReflection = false;
98112
EnableDebugging = false;
99113
EngineMode = JsEngineMode.Auto;
100114
#if !NETSTANDARD1_3

src/MsieJavaScriptEngine/JsRt/Edge/ChakraEdgeJsRtJsEngine.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ internal sealed class ChakraEdgeJsRtJsEngine : ChakraJsRtJsEngineBase
6161
public ChakraEdgeJsRtJsEngine(JsEngineSettings settings)
6262
: base(settings)
6363
{
64-
_typeMapper = new EdgeTypeMapper();
64+
_typeMapper = new EdgeTypeMapper(settings.AllowReflection);
6565

6666
try
6767
{

0 commit comments

Comments
 (0)