Skip to content

Commit

Permalink
Function call performance improvements (#703)
Browse files Browse the repository at this point in the history
* use adapting HybridDictionary for DeclarativeEnvironmentRecord
* lazily materialize arguments when needed
* return ArgumentsInstance to pool when we can
* return compatibility with RavenDB usage
* remove function callback logic from DeclarativeEnvironmentRecord
  • Loading branch information
lahma committed Jan 20, 2020
1 parent 2289f9c commit 026ebc7
Show file tree
Hide file tree
Showing 25 changed files with 629 additions and 181 deletions.
74 changes: 74 additions & 0 deletions Jint.Benchmark/DictionaryBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System.Collections.Generic;
using Jint.Collections;
using BenchmarkDotNet.Attributes;

namespace Jint.Benchmark
{
[MemoryDiagnoser]
public class DictionaryBenchmark
{
private static readonly string[] _keys =
{
"some",
"key and",
"another",
"varying",
"---the --",
"keys and more",
"aa bbb",
"asasd asd ",
"asdsad asd as s",
"asdadsasa",
"23323232323",
"asdadsada sa213"
};

[Params(0, 2, 3, 5, 8, 9, 10)]
public int N { get; set; }

[Benchmark]
public void HybridDictionary()
{
var hybridDictionary = new HybridDictionary<string, object>();
for (var i = 0; i < N; i++)
{
hybridDictionary.Add(_keys[i], _keys);
}

foreach (var key in _keys)
{
hybridDictionary.ContainsKey(key);
}
}

[Benchmark]
public void Dictionary()
{
var dictionary = new Dictionary<string, object>();
for (var i = 0; i < N; i++)
{
dictionary.Add(_keys[i], _keys);
}

foreach (var key in _keys)
{
dictionary.ContainsKey(key);
}
}

[Benchmark]
public void StringDictionarySlim()
{
var dictionary = new StringDictionarySlim<object>();
for (var i = 0; i < N; i++)
{
dictionary[_keys[i]] =_keys;
}

foreach (var key in _keys)
{
dictionary.ContainsKey(key);
}
}
}
}
2 changes: 2 additions & 0 deletions Jint.Benchmark/Jint.Benchmark.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<GenerateAssemblyCopyrightAttribute>false</GenerateAssemblyCopyrightAttribute>
<GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>false</GenerateAssemblyFileVersionAttribute>
<AssemblyOriginatorKeyFile>..\Jint\Jint.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
Expand Down
88 changes: 13 additions & 75 deletions Jint.Benchmark/UncacheableExpressionsBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,18 @@ public class UncacheableExpressionsBenchmark
private string targetObject;
private JsValue[] targetJsObject;

private const string script = @"
private const string NonArrowFunctionScript = @"
function output(d) {
var doc = d.SubDocuments.find(function(x){return x.Id==='testing';});
return { Id : d.Id, Deleted : d.Deleted, SubTestId : (doc!==null&&doc!==undefined)?doc.Id:null, Values : d.SubDocuments.map(function(x){return {TargetId:x.TargetId,TargetValue:x.TargetValue,SubDocuments:x.SubDocuments.filter(function(s){return (s!==null&&s!==undefined);}).map(function(s){return {TargetId:s.TargetId,TargetValue:s.TargetValue};})};}) };
}
";

private const string ArrowFunctionScript = @"
function output(d) {
var doc = d.SubDocuments.find(x => x.Id==='testing');
return { Id : d.Id, Deleted : d.Deleted, SubTestId : (doc!==null&&doc!==undefined)?doc.Id:null, Values : d.SubDocuments.map(x => ({ TargetId:x.TargetId,TargetValue:x.TargetValue,SubDocuments:x.SubDocuments.filter(s => (s!==null&&s!==undefined)).map(s => ({ TargetId: s.TargetId, TargetValue: s.TargetValue}))})) };
}
";

private Engine engine;
Expand Down Expand Up @@ -72,7 +79,7 @@ public void Setup()
}
}

CreateEngine();
CreateEngine(Arrow ? ArrowFunctionScript : NonArrowFunctionScript);
}

private static void InitializeEngine(Options options)
Expand All @@ -87,6 +94,9 @@ private static void InitializeEngine(Options options)
[Params(500)]
public int N { get; set; }

[Params(true, false)]
public bool Arrow { get; set; }

[Benchmark]
public void Benchmark()
{
Expand All @@ -97,84 +107,12 @@ public void Benchmark()
}
}

private void CreateEngine()
private void CreateEngine(string script)
{
engine = new Engine(InitializeEngine);
engine.Execute(Polyfills);
engine.Execute(script);
engine.Execute(targetObject);
targetJsObject = new[] {engine.GetValue("d")};
}

private const string Polyfills = @"
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
if (!String.prototype.endsWith) {
String.prototype.endsWith = function (searchStr, position) {
if (!(position < this.length))
position = this.length;
else
position |= 0; // round position
return this.substr(position - searchStr.length,
searchStr.length) === searchStr;
};
}
//https://github.com/jsPolyfill/Array.prototype.find/blob/master/find.js
if (!Array.prototype.find) {
Array.prototype.find = Array.prototype.find || function(callback) {
if (this === null) {
throw new TypeError('Array.prototype.find called on null or undefined');
} else if (typeof callback !== 'function') {
throw new TypeError('callback must be a function');
}
var list = Object(this);
// Makes sures is always has an positive integer as length.
var length = list.length >>> 0;
var thisArg = arguments[1];
for (var i = 0; i < length; i++) {
var element = list[i];
if ( callback.call(thisArg, element, i, list) ) {
return element;
}
}
};
}
if (!Array.prototype.fastFilter) {
Array.prototype.fastFilter = function(callback) {
var results = [];
var item;
var len = this.length;
for (var i = 0, len = len; i < len; i++) {
item = this[i];
if (callback(item)) results.push(item);
}
return results;
}
}
if (!Array.prototype.fastMap) {
Array.prototype.fastMap = function(callback) {
var h = [];
var len = this.length;
for (var i = 0, len = len; i < len; i++) {
h.push(callback(this[i]));
}
return h;
}
}
if (!Array.prototype.fastFind) {
Array.prototype.fastFind = function(callback) {
var item;
var len = this.length;
for (var i = 0, len = len; i < len; i++) {
item = this[i];
if (callback(item)) return item;
}
}
}
";
}
}
3 changes: 3 additions & 0 deletions Jint.Tests.Ecma/Jint.Tests.Ecma.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<None Remove="TestCases\ch*\**" />
</ItemGroup>
</Project>
4 changes: 4 additions & 0 deletions Jint.Tests.Test262/Jint.Tests.Test262.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<None Remove="harness\**" />
<None Remove="test\**" />
</ItemGroup>
</Project>
3 changes: 3 additions & 0 deletions Jint/AssemblyInfoExtras.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Jint.Benchmark, PublicKey=0024000004800000940000000602000000240000525341310004000001000100bf2553c9f214cb21f1f64ed62cadad8fe4f2fa11322a5dfa1d650743145c6085aba05b145b29867af656e0bb9bfd32f5d0deb1668263a38233e7e8e5bad1a3c6edd3f2ec6c512668b4aa797283101444628650949641b4f7cb16707efba542bb754afe87ce956f3a5d43f450d14364eb9571cbf213d1061852fb9dd47a6c05c4")]

0 comments on commit 026ebc7

Please sign in to comment.