Skip to content

Commit ae27bbc

Browse files
committed
Prevents a early destruction of pre-compiled scripts by the garbage collector
1 parent 9664fa7 commit ae27bbc

File tree

4 files changed

+78
-153
lines changed

4 files changed

+78
-153
lines changed

src/MsieJavaScriptEngine/JsRt/Edge/ChakraEdgeJsRtJsEngine.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1140,6 +1140,10 @@ public override void Execute(PrecompiledScript precompiledScript)
11401140
{
11411141
throw WrapJsException(e);
11421142
}
1143+
finally
1144+
{
1145+
GC.KeepAlive(precompiledScript);
1146+
}
11431147
}
11441148
});
11451149
}

src/MsieJavaScriptEngine/JsRt/Ie/ChakraIeJsRtJsEngine.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,6 +1208,10 @@ public override void Execute(PrecompiledScript precompiledScript)
12081208
{
12091209
throw WrapJsException(e);
12101210
}
1211+
finally
1212+
{
1213+
GC.KeepAlive(precompiledScript);
1214+
}
12111215
}
12121216
});
12131217
}

test/MsieJavaScriptEngine.Benchmarks/JsExecutionBenchmark.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ private static void TransliterateStrings(Func<MsieJsEngine> createJsEngine, bool
172172
}
173173

174174
// Assert
175-
for (int itemIndex = 1; itemIndex < ItemCount; itemIndex++)
175+
for (int itemIndex = 0; itemIndex < ItemCount; itemIndex++)
176176
{
177177
Assert.Equal(_targetOutputStrings[itemIndex], outputStrings[itemIndex]);
178178
}

test/MsieJavaScriptEngine.Test.Common/PrecompilationTestsBase.cs

Lines changed: 69 additions & 152 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.IO;
22
using System.Reflection;
3+
using System.Threading.Tasks;
34

45
using NUnit.Framework;
56

@@ -45,28 +46,16 @@ function declinationOfSeconds(number) {
4546
return declensionOfNumerals(number, ['секунда', 'секунды', 'секунд']);
4647
}";
4748
const string functionName = "declinationOfSeconds";
49+
const int itemCount = 4;
4850

49-
const int input0 = 0;
50-
const string targetOutput0 = "секунд";
51-
52-
const int input1 = 1;
53-
const string targetOutput1 = "секунда";
54-
55-
const int input2 = 42;
56-
const string targetOutput2 = "секунды";
57-
58-
const int input3 = 600;
59-
const string targetOutput3 = "секунд";
51+
int[] inputSeconds = new int[itemCount] { 0, 1, 42, 600 };
52+
string[] targetOutputStrings = new string[itemCount] { "секунд", "секунда", "секунды", "секунд" };
53+
string[] outputStrings = new string[itemCount];
6054

6155
// Act
6256
bool supportsScriptPrecompilation = false;
6357
PrecompiledScript precompiledCode = null;
6458

65-
string output0 = string.Empty;
66-
string output1 = string.Empty;
67-
string output2 = string.Empty;
68-
string output3 = string.Empty;
69-
7059
using (var jsEngine = CreateJsEngine())
7160
{
7261
supportsScriptPrecompilation = jsEngine.SupportsScriptPrecompilation;
@@ -75,38 +64,29 @@ function declinationOfSeconds(number) {
7564
precompiledCode = jsEngine.Precompile(libraryCode, "declinationOfSeconds.js");
7665

7766
jsEngine.Execute(precompiledCode);
78-
output0 = jsEngine.CallFunction<string>(functionName, input0);
67+
outputStrings[0] = jsEngine.CallFunction<string>(functionName, inputSeconds[0]);
7968
}
8069
}
8170

8271
if (supportsScriptPrecompilation)
8372
{
84-
using (var firstJsEngine = CreateJsEngine())
85-
{
86-
firstJsEngine.Execute(precompiledCode);
87-
output1 = firstJsEngine.CallFunction<string>(functionName, input1);
88-
}
89-
90-
using (var secondJsEngine = CreateJsEngine())
91-
{
92-
secondJsEngine.Execute(precompiledCode);
93-
output2 = secondJsEngine.CallFunction<string>(functionName, input2);
94-
}
95-
96-
using (var thirdJsEngine = CreateJsEngine())
97-
{
98-
thirdJsEngine.Execute(precompiledCode);
99-
output3 = thirdJsEngine.CallFunction<string>(functionName, input3);
100-
}
73+
Parallel.For(1, itemCount, itemIndex =>
74+
{
75+
using (var jsEngine = CreateJsEngine())
76+
{
77+
jsEngine.Execute(precompiledCode);
78+
outputStrings[itemIndex] = jsEngine.CallFunction<string>(functionName, inputSeconds[itemIndex]);
79+
}
80+
});
10181
}
10282

10383
// Assert
10484
if (supportsScriptPrecompilation)
10585
{
106-
Assert.AreEqual(targetOutput0, output0);
107-
Assert.AreEqual(targetOutput1, output1);
108-
Assert.AreEqual(targetOutput2, output2);
109-
Assert.AreEqual(targetOutput3, output3);
86+
for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
87+
{
88+
Assert.AreEqual(targetOutputStrings[itemIndex], outputStrings[itemIndex]);
89+
}
11090
}
11191
}
11292

@@ -116,28 +96,16 @@ public virtual void ExecutionOfPrecompiledFileIsCorrect()
11696
// Arrange
11797
string filePath = Path.GetFullPath(Path.Combine(_baseDirectoryPath, "SharedFiles/declinationOfMinutes.js"));
11898
const string functionName = "declinationOfMinutes";
99+
const int itemCount = 4;
119100

120-
const int input0 = 0;
121-
const string targetOutput0 = "минут";
122-
123-
const int input1 = 1;
124-
const string targetOutput1 = "минута";
125-
126-
const int input2 = 22;
127-
const string targetOutput2 = "минуты";
128-
129-
const int input3 = 88;
130-
const string targetOutput3 = "минут";
101+
int[] inputMinutes = new int[itemCount] { 0, 1, 22, 88 };
102+
string[] targetOutputStrings = new string[itemCount] { "минут", "минута", "минуты", "минут" };
103+
string[] outputStrings = new string[itemCount];
131104

132105
// Act
133106
bool supportsScriptPrecompilation = false;
134107
PrecompiledScript precompiledFile = null;
135108

136-
string output0 = string.Empty;
137-
string output1 = string.Empty;
138-
string output2 = string.Empty;
139-
string output3 = string.Empty;
140-
141109
using (var jsEngine = CreateJsEngine())
142110
{
143111
supportsScriptPrecompilation = jsEngine.SupportsScriptPrecompilation;
@@ -146,38 +114,29 @@ public virtual void ExecutionOfPrecompiledFileIsCorrect()
146114
precompiledFile = jsEngine.PrecompileFile(filePath);
147115

148116
jsEngine.Execute(precompiledFile);
149-
output0 = jsEngine.CallFunction<string>(functionName, input0);
117+
outputStrings[0] = jsEngine.CallFunction<string>(functionName, inputMinutes[0]);
150118
}
151119
}
152120

153121
if (supportsScriptPrecompilation)
154122
{
155-
using (var firstJsEngine = CreateJsEngine())
156-
{
157-
firstJsEngine.Execute(precompiledFile);
158-
output1 = firstJsEngine.CallFunction<string>(functionName, input1);
159-
}
160-
161-
using (var secondJsEngine = CreateJsEngine())
162-
{
163-
secondJsEngine.Execute(precompiledFile);
164-
output2 = secondJsEngine.CallFunction<string>(functionName, input2);
165-
}
166-
167-
using (var thirdJsEngine = CreateJsEngine())
168-
{
169-
thirdJsEngine.Execute(precompiledFile);
170-
output3 = thirdJsEngine.CallFunction<string>(functionName, input3);
171-
}
123+
Parallel.For(1, itemCount, itemIndex =>
124+
{
125+
using (var jsEngine = CreateJsEngine())
126+
{
127+
jsEngine.Execute(precompiledFile);
128+
outputStrings[itemIndex] = jsEngine.CallFunction<string>(functionName, inputMinutes[itemIndex]);
129+
}
130+
});
172131
}
173132

174133
// Assert
175134
if (supportsScriptPrecompilation)
176135
{
177-
Assert.AreEqual(targetOutput0, output0);
178-
Assert.AreEqual(targetOutput1, output1);
179-
Assert.AreEqual(targetOutput2, output2);
180-
Assert.AreEqual(targetOutput3, output3);
136+
for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
137+
{
138+
Assert.AreEqual(targetOutputStrings[itemIndex], outputStrings[itemIndex]);
139+
}
181140
}
182141
}
183142

@@ -187,28 +146,16 @@ public virtual void ExecutionOfPrecompiledResourceByNameAndTypeIsCorrect()
187146
// Arrange
188147
const string resourceName = "Resources.declinationOfHours.js";
189148
const string functionName = "declinationOfHours";
149+
const int itemCount = 4;
190150

191-
const int input0 = 0;
192-
const string targetOutput0 = "часов";
193-
194-
const int input1 = 1;
195-
const string targetOutput1 = "час";
196-
197-
const int input2 = 24;
198-
const string targetOutput2 = "часа";
199-
200-
const int input3 = 48;
201-
const string targetOutput3 = "часов";
151+
int[] inputHours = new int[itemCount] { 0, 1, 24, 48 };
152+
string[] targetOutputStrings = new string[itemCount] { "часов", "час", "часа", "часов" };
153+
string[] outputStrings = new string[itemCount];
202154

203155
// Act
204156
bool supportsScriptPrecompilation = false;
205157
PrecompiledScript precompiledResource = null;
206158

207-
string output0 = string.Empty;
208-
string output1 = string.Empty;
209-
string output2 = string.Empty;
210-
string output3 = string.Empty;
211-
212159
using (var jsEngine = CreateJsEngine())
213160
{
214161
supportsScriptPrecompilation = jsEngine.SupportsScriptPrecompilation;
@@ -217,38 +164,29 @@ public virtual void ExecutionOfPrecompiledResourceByNameAndTypeIsCorrect()
217164
precompiledResource = jsEngine.PrecompileResource(resourceName, typeof(PrecompilationTestsBase));
218165

219166
jsEngine.Execute(precompiledResource);
220-
output0 = jsEngine.CallFunction<string>(functionName, input0);
167+
outputStrings[0] = jsEngine.CallFunction<string>(functionName, inputHours[0]);
221168
}
222169
}
223170

224171
if (supportsScriptPrecompilation)
225172
{
226-
using (var firstJsEngine = CreateJsEngine())
227-
{
228-
firstJsEngine.Execute(precompiledResource);
229-
output1 = firstJsEngine.CallFunction<string>(functionName, input1);
230-
}
231-
232-
using (var secondJsEngine = CreateJsEngine())
233-
{
234-
secondJsEngine.Execute(precompiledResource);
235-
output2 = secondJsEngine.CallFunction<string>(functionName, input2);
236-
}
237-
238-
using (var thirdJsEngine = CreateJsEngine())
239-
{
240-
thirdJsEngine.Execute(precompiledResource);
241-
output3 = thirdJsEngine.CallFunction<string>(functionName, input3);
242-
}
173+
Parallel.For(1, itemCount, itemIndex =>
174+
{
175+
using (var jsEngine = CreateJsEngine())
176+
{
177+
jsEngine.Execute(precompiledResource);
178+
outputStrings[itemIndex] = jsEngine.CallFunction<string>(functionName, inputHours[itemIndex]);
179+
}
180+
});
243181
}
244182

245183
// Assert
246184
if (supportsScriptPrecompilation)
247185
{
248-
Assert.AreEqual(targetOutput0, output0);
249-
Assert.AreEqual(targetOutput1, output1);
250-
Assert.AreEqual(targetOutput2, output2);
251-
Assert.AreEqual(targetOutput3, output3);
186+
for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
187+
{
188+
Assert.AreEqual(targetOutputStrings[itemIndex], outputStrings[itemIndex]);
189+
}
252190
}
253191
}
254192

@@ -258,28 +196,16 @@ public virtual void ExecutionOfPrecompiledResourceByNameAndAssemblyIsCorrect()
258196
// Arrange
259197
const string resourceName = "MsieJavaScriptEngine.Test.Common.Resources.declinationOfDays.js";
260198
const string functionName = "declinationOfDays";
199+
const int itemCount = 4;
261200

262-
const int input0 = 0;
263-
const string targetOutput0 = "дней";
264-
265-
const int input1 = 1;
266-
const string targetOutput1 = "день";
267-
268-
const int input2 = 3;
269-
const string targetOutput2 = "дня";
270-
271-
const int input3 = 80;
272-
const string targetOutput3 = "дней";
201+
int[] inputDays = new int[itemCount] { 0, 1, 3, 80 };
202+
string[] targetOutputStrings = new string[itemCount] { "дней", "день", "дня", "дней" };
203+
string[] outputStrings = new string[itemCount];
273204

274205
// Act
275206
bool supportsScriptPrecompilation = false;
276207
PrecompiledScript precompiledResource = null;
277208

278-
string output0 = string.Empty;
279-
string output1 = string.Empty;
280-
string output2 = string.Empty;
281-
string output3 = string.Empty;
282-
283209
using (var jsEngine = CreateJsEngine())
284210
{
285211
supportsScriptPrecompilation = jsEngine.SupportsScriptPrecompilation;
@@ -293,38 +219,29 @@ public virtual void ExecutionOfPrecompiledResourceByNameAndAssemblyIsCorrect()
293219
);
294220

295221
jsEngine.Execute(precompiledResource);
296-
output0 = jsEngine.CallFunction<string>(functionName, input0);
222+
outputStrings[0] = jsEngine.CallFunction<string>(functionName, inputDays[0]);
297223
}
298224
}
299225

300226
if (supportsScriptPrecompilation)
301227
{
302-
using (var firstJsEngine = CreateJsEngine())
303-
{
304-
firstJsEngine.Execute(precompiledResource);
305-
output1 = firstJsEngine.CallFunction<string>(functionName, input1);
306-
}
307-
308-
using (var secondJsEngine = CreateJsEngine())
309-
{
310-
secondJsEngine.Execute(precompiledResource);
311-
output2 = secondJsEngine.CallFunction<string>(functionName, input2);
312-
}
313-
314-
using (var thirdJsEngine = CreateJsEngine())
315-
{
316-
thirdJsEngine.Execute(precompiledResource);
317-
output3 = thirdJsEngine.CallFunction<string>(functionName, input3);
318-
}
228+
Parallel.For(1, itemCount, itemIndex =>
229+
{
230+
using (var jsEngine = CreateJsEngine())
231+
{
232+
jsEngine.Execute(precompiledResource);
233+
outputStrings[itemIndex] = jsEngine.CallFunction<string>(functionName, inputDays[itemIndex]);
234+
}
235+
});
319236
}
320237

321238
// Assert
322239
if (supportsScriptPrecompilation)
323240
{
324-
Assert.AreEqual(targetOutput0, output0);
325-
Assert.AreEqual(targetOutput1, output1);
326-
Assert.AreEqual(targetOutput2, output2);
327-
Assert.AreEqual(targetOutput3, output3);
241+
for (int itemIndex = 0; itemIndex < itemCount; itemIndex++)
242+
{
243+
Assert.AreEqual(targetOutputStrings[itemIndex], outputStrings[itemIndex]);
244+
}
328245
}
329246
}
330247

0 commit comments

Comments
 (0)