Skip to content

Commit 4401dec

Browse files
committed
In version for .NET Core improved a embedding of delegates and types
1 parent 1b3827b commit 4401dec

File tree

7 files changed

+137
-33
lines changed

7 files changed

+137
-33
lines changed

src/MsieJavaScriptEngine/JsRt/Edge/EdgeTypeMapper.cs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ public override EdgeJsValue MapToScriptType(object value)
123123
public override object MapToHostType(EdgeJsValue value)
124124
{
125125
JsValueType valueType = value.ValueType;
126-
object result;
126+
object result = null;
127127

128128
switch (valueType)
129129
{
@@ -142,8 +142,23 @@ public override object MapToHostType(EdgeJsValue value)
142142
case JsValueType.String:
143143
result = value.ToString();
144144
break;
145+
#if NETSTANDARD
146+
case JsValueType.Function:
147+
EdgeJsPropertyId externalObjectPropertyId = EdgeJsPropertyId.FromString(ExternalObjectPropertyName);
148+
if (value.HasProperty(externalObjectPropertyId))
149+
{
150+
EdgeJsValue externalObjectValue = value.GetProperty(externalObjectPropertyId);
151+
result = externalObjectValue.HasExternalData ?
152+
GCHandle.FromIntPtr(externalObjectValue.ExternalData).Target : null;
153+
}
154+
155+
result = result ?? value.ConvertToObject();
156+
break;
157+
#endif
145158
case JsValueType.Object:
159+
#if !NETSTANDARD
146160
case JsValueType.Function:
161+
#endif
147162
case JsValueType.Error:
148163
case JsValueType.Array:
149164
#if NETSTANDARD
@@ -225,10 +240,10 @@ private EdgeEmbeddedObject CreateEmbeddedFunction(Delegate del)
225240

226241
GCHandle delHandle = GCHandle.Alloc(del);
227242
IntPtr delPtr = GCHandle.ToIntPtr(delHandle);
228-
EdgeJsValue prototypeValue = EdgeJsValue.CreateExternalObject(delPtr, _embeddedObjectFinalizeCallback);
243+
EdgeJsValue objValue = EdgeJsValue.CreateExternalObject(delPtr, _embeddedObjectFinalizeCallback);
229244

230245
EdgeJsValue functionValue = EdgeJsValue.CreateFunction(nativeFunction);
231-
functionValue.Prototype = prototypeValue;
246+
SetNonEnumerableProperty(functionValue, ExternalObjectPropertyName, objValue);
232247

233248
var embeddedObject = new EdgeEmbeddedObject(del, functionValue,
234249
new List<EdgeJsNativeFunction> { nativeFunction });
@@ -300,14 +315,13 @@ protected override EdgeEmbeddedType CreateEmbeddedType(Type type)
300315
return resultValue;
301316
};
302317

303-
string embeddedTypeKey = type.AssemblyQualifiedName;
304-
GCHandle embeddedTypeKeyHandle = GCHandle.Alloc(embeddedTypeKey);
305-
IntPtr embeddedTypeKeyPtr = GCHandle.ToIntPtr(embeddedTypeKeyHandle);
306-
EdgeJsValue prototypeValue = EdgeJsValue.CreateExternalObject(embeddedTypeKeyPtr,
318+
GCHandle embeddedTypeHandle = GCHandle.Alloc(type);
319+
IntPtr embeddedTypePtr = GCHandle.ToIntPtr(embeddedTypeHandle);
320+
EdgeJsValue objValue = EdgeJsValue.CreateExternalObject(embeddedTypePtr,
307321
_embeddedTypeFinalizeCallback);
308322

309323
EdgeJsValue typeValue = EdgeJsValue.CreateFunction(nativeConstructorFunction);
310-
typeValue.Prototype = prototypeValue;
324+
SetNonEnumerableProperty(typeValue, ExternalObjectPropertyName, objValue);
311325

312326
var embeddedType = new EdgeEmbeddedType(type, typeValue,
313327
new List<EdgeJsNativeFunction> { nativeConstructorFunction });
@@ -624,14 +638,26 @@ private void ProjectMethods(EdgeEmbeddedItem externalItem)
624638
}
625639

626640
[MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
627-
private void FreezeObject(EdgeJsValue objValue)
641+
private static void FreezeObject(EdgeJsValue objValue)
628642
{
629643
EdgeJsValue freezeMethodValue = EdgeJsValue.GlobalObject
630644
.GetProperty("Object")
631645
.GetProperty("freeze")
632646
;
633647
freezeMethodValue.CallFunction(objValue);
634648
}
649+
650+
[MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
651+
private static void SetNonEnumerableProperty(EdgeJsValue objValue, string name, EdgeJsValue value)
652+
{
653+
EdgeJsValue descriptorValue = EdgeJsValue.CreateObject();
654+
descriptorValue.SetProperty("enumerable", EdgeJsValue.False, true);
655+
descriptorValue.SetProperty("writable", EdgeJsValue.True, true);
656+
657+
EdgeJsPropertyId id = EdgeJsPropertyId.FromString(name);
658+
objValue.DefineProperty(id, descriptorValue);
659+
objValue.SetProperty(id, value, true);
660+
}
635661
#endif
636662
}
637663
}

src/MsieJavaScriptEngine/JsRt/Ie/IeTypeMapper.cs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public override IeJsValue MapToScriptType(object value)
120120
public override object MapToHostType(IeJsValue value)
121121
{
122122
JsValueType valueType = value.ValueType;
123-
object result;
123+
object result = null;
124124

125125
switch (valueType)
126126
{
@@ -139,8 +139,23 @@ public override object MapToHostType(IeJsValue value)
139139
case JsValueType.String:
140140
result = value.ToString();
141141
break;
142+
#if NETSTANDARD
143+
case JsValueType.Function:
144+
IeJsPropertyId externalObjectPropertyId = IeJsPropertyId.FromString(ExternalObjectPropertyName);
145+
if (value.HasProperty(externalObjectPropertyId))
146+
{
147+
IeJsValue externalObjectValue = value.GetProperty(externalObjectPropertyId);
148+
result = externalObjectValue.HasExternalData ?
149+
GCHandle.FromIntPtr(externalObjectValue.ExternalData).Target : null;
150+
}
151+
152+
result = result ?? value.ConvertToObject();
153+
break;
154+
#endif
142155
case JsValueType.Object:
156+
#if !NETSTANDARD
143157
case JsValueType.Function:
158+
#endif
144159
case JsValueType.Error:
145160
case JsValueType.Array:
146161
#if NETSTANDARD
@@ -222,10 +237,10 @@ private IeEmbeddedObject CreateEmbeddedFunction(Delegate del)
222237

223238
GCHandle delHandle = GCHandle.Alloc(del);
224239
IntPtr delPtr = GCHandle.ToIntPtr(delHandle);
225-
IeJsValue prototypeValue = IeJsValue.CreateExternalObject(delPtr, _embeddedObjectFinalizeCallback);
240+
IeJsValue objValue = IeJsValue.CreateExternalObject(delPtr, _embeddedObjectFinalizeCallback);
226241

227242
IeJsValue functionValue = IeJsValue.CreateFunction(nativeFunction);
228-
functionValue.Prototype = prototypeValue;
243+
SetNonEnumerableProperty(functionValue, ExternalObjectPropertyName, objValue);
229244

230245
var embeddedObject = new IeEmbeddedObject(del, functionValue,
231246
new List<IeJsNativeFunction> { nativeFunction });
@@ -297,14 +312,13 @@ protected override IeEmbeddedType CreateEmbeddedType(Type type)
297312
return resultValue;
298313
};
299314

300-
string embeddedTypeKey = type.AssemblyQualifiedName;
301-
GCHandle embeddedTypeKeyHandle = GCHandle.Alloc(embeddedTypeKey);
302-
IntPtr embeddedTypeKeyPtr = GCHandle.ToIntPtr(embeddedTypeKeyHandle);
303-
IeJsValue prototypeValue = IeJsValue.CreateExternalObject(embeddedTypeKeyPtr,
315+
GCHandle embeddedTypeHandle = GCHandle.Alloc(type);
316+
IntPtr embeddedTypePtr = GCHandle.ToIntPtr(embeddedTypeHandle);
317+
IeJsValue objValue = IeJsValue.CreateExternalObject(embeddedTypePtr,
304318
_embeddedTypeFinalizeCallback);
305319

306320
IeJsValue typeValue = IeJsValue.CreateFunction(nativeConstructorFunction);
307-
typeValue.Prototype = prototypeValue;
321+
SetNonEnumerableProperty(typeValue, ExternalObjectPropertyName, objValue);
308322

309323
var embeddedType = new IeEmbeddedType(type, typeValue,
310324
new List<IeJsNativeFunction> { nativeConstructorFunction });
@@ -621,13 +635,25 @@ private void ProjectMethods(IeEmbeddedItem externalItem)
621635
}
622636

623637
[MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
624-
private void FreezeObject(IeJsValue objValue)
638+
private static void FreezeObject(IeJsValue objValue)
625639
{
626640
IeJsValue objectValue = IeJsValue.GlobalObject.GetProperty("Object");
627641
IeJsValue freezeMethodValue = objectValue.GetProperty("freeze");
628642

629643
freezeMethodValue.CallFunction(objectValue, objValue);
630644
}
645+
646+
[MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]
647+
private static void SetNonEnumerableProperty(IeJsValue objValue, string name, IeJsValue value)
648+
{
649+
IeJsValue descriptorValue = IeJsValue.CreateObject();
650+
descriptorValue.SetProperty("enumerable", IeJsValue.False, true);
651+
descriptorValue.SetProperty("writable", IeJsValue.True, true);
652+
653+
IeJsPropertyId id = IeJsPropertyId.FromString(name);
654+
objValue.DefineProperty(id, descriptorValue);
655+
objValue.SetProperty(id, value, true);
656+
}
631657
#endif
632658
}
633659
}

src/MsieJavaScriptEngine/JsRt/TypeMapper.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ internal abstract class TypeMapper<TValue, TFunction> : IDisposable
2525
where TFunction : Delegate
2626
{
2727
#if NETSTANDARD
28+
/// <summary>
29+
/// Name of property to store the external object
30+
/// </summary>
31+
protected const string ExternalObjectPropertyName = "_MsieJavaScriptEngine_externalObject";
32+
2833
/// <summary>
2934
/// Storage for lazy-initialized embedded objects
3035
/// </summary>
@@ -229,8 +234,9 @@ private void EmbeddedTypeFinalizeCallback(IntPtr ptr)
229234
return;
230235
}
231236

232-
GCHandle embeddedTypeKeyHandle = GCHandle.FromIntPtr(ptr);
233-
var embeddedTypeKey = (string)embeddedTypeKeyHandle.Target;
237+
GCHandle embeddedTypeHandle = GCHandle.FromIntPtr(ptr);
238+
var type = (Type)embeddedTypeHandle.Target;
239+
string embeddedTypeKey = type.AssemblyQualifiedName;
234240
var lazyEmbeddedTypes = _lazyEmbeddedTypes;
235241

236242
if (!string.IsNullOrEmpty(embeddedTypeKey) && lazyEmbeddedTypes != null)
@@ -243,7 +249,7 @@ private void EmbeddedTypeFinalizeCallback(IntPtr ptr)
243249
}
244250
}
245251

246-
embeddedTypeKeyHandle.Free();
252+
embeddedTypeHandle.Free();
247253
}
248254

249255
[MethodImpl((MethodImplOptions)256 /* AggressiveInlining */)]

src/MsieJavaScriptEngine/MsieJavaScriptEngine.csproj

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@
2121
<RepositoryUrl>https://github.com/Taritsyn/MsieJavaScriptEngine</RepositoryUrl>
2222
<RepositoryType>git</RepositoryType>
2323
<PackageTags>JavaScript;ECMAScript;MSIE;IE;Edge;Chakra</PackageTags>
24-
<PackageReleaseNotes>1. Fixed a error, that occurred in the `Classic` mode during calling an embedded delegate, which does not return a result;
25-
2. Fixed a error, that occurred during setting a value to field of embedded type;
26-
3. Improved a performance of the embedding of objects and types;
27-
4. Accelerated a conversion of script types to host types.</PackageReleaseNotes>
24+
<PackageReleaseNotes>In version for .NET Core improved a embedding of delegates and types.</PackageReleaseNotes>
2825
<NeutralLanguage>en-US</NeutralLanguage>
2926
<PackageOutputPath>../../nuget</PackageOutputPath>
3027
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>

src/MsieJavaScriptEngine/readme.txt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@
2121
=============
2222
RELEASE NOTES
2323
=============
24-
1. Fixed a error, that occurred in the `Classic` mode during calling an embedded
25-
delegate, which does not return a result;
26-
2. Fixed a error, that occurred during setting a value to field of embedded
27-
type;
28-
3. Improved a performance of the embedding of objects and types;
29-
4. Accelerated a conversion of script types to host types.
24+
In version for .NET Core improved a embedding of delegates and types.
3025

3126
============
3227
PROJECT SITE

test/MsieJavaScriptEngine.Test.ChakraEdgeJsRt/InteropTests.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
using NUnit.Framework;
1+
#if NETCOREAPP
2+
using System;
3+
4+
#endif
5+
using NUnit.Framework;
26

37
using MsieJavaScriptEngine.Test.Common;
48

@@ -18,5 +22,28 @@ protected override MsieJsEngine CreateJsEngine()
1822

1923
return jsEngine;
2024
}
25+
#if NETCOREAPP
26+
27+
[Test]
28+
public void EmbeddedInstanceOfDelegateHasFunctionPrototype()
29+
{
30+
// Arrange
31+
var someFunc = new Func<int>(() => 42);
32+
33+
const string input = "Object.getPrototypeOf(embeddedFunc) === Function.prototype";
34+
35+
// Act
36+
bool output;
37+
38+
using (var jsEngine = CreateJsEngine())
39+
{
40+
jsEngine.EmbedHostObject("embeddedFunc", someFunc);
41+
output = jsEngine.Evaluate<bool>(input);
42+
}
43+
44+
// Assert
45+
Assert.True(output);
46+
}
47+
#endif
2148
}
2249
}

test/MsieJavaScriptEngine.Test.ChakraIeJsRt/InteropTests.cs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
using NUnit.Framework;
1+
#if NETCOREAPP
2+
using System;
3+
4+
#endif
5+
using NUnit.Framework;
26

37
using MsieJavaScriptEngine.Test.Common;
48

@@ -18,5 +22,28 @@ protected override MsieJsEngine CreateJsEngine()
1822

1923
return jsEngine;
2024
}
25+
#if NETCOREAPP
26+
27+
[Test]
28+
public void EmbeddedInstanceOfDelegateHasFunctionPrototype()
29+
{
30+
// Arrange
31+
var someFunc = new Func<int>(() => 42);
32+
33+
const string input = "Object.getPrototypeOf(embeddedFunc) === Function.prototype";
34+
35+
// Act
36+
bool output;
37+
38+
using (var jsEngine = CreateJsEngine())
39+
{
40+
jsEngine.EmbedHostObject("embeddedFunc", someFunc);
41+
output = jsEngine.Evaluate<bool>(input);
42+
}
43+
44+
// Assert
45+
Assert.True(output);
46+
}
47+
#endif
2148
}
2249
}

0 commit comments

Comments
 (0)