Skip to content

Commit

Permalink
Merge branch 'sebastienros:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
scgm0 authored Dec 16, 2023
2 parents 5475c06 + 93c5ee5 commit 72014dc
Show file tree
Hide file tree
Showing 40 changed files with 906 additions and 529 deletions.
7 changes: 4 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
<PackageVersion Include="Esprima" Version="3.0.2" />
<PackageVersion Include="Flurl.Http.Signed" Version="3.2.4" />
<PackageVersion Include="Jurassic" Version="3.2.7" />
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.110" />
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.116" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageVersion Include="Microsoft.Extensions.TimeProvider.Testing" Version="8.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageVersion Include="MongoDB.Bson.signed" Version="2.19.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="NiL.JS" Version="2.5.1674" />
<PackageVersion Include="NodaTime" Version="3.1.9" />
<PackageVersion Include="NUnit" Version="3.14.0" />
<PackageVersion Include="NUnit" Version="4.0.0" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.0" />
<PackageVersion Include="Spectre.Console.Cli" Version="0.45.0" />
Expand All @@ -28,6 +29,6 @@
<ItemGroup>
<GlobalPackageReference Include="GitHubActionsTestLogger" Version="2.3.3" />
<GlobalPackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<GlobalPackageReference Include="PolySharp" Version="1.13.2" />
<GlobalPackageReference Include="PolySharp" Version="1.14.0" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Jint.Benchmark/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ dotnet run -c Release --allCategories EngineComparison
* tests are run in global engine strict mode, as YantraJS always uses strict mode which improves performance
* `Jint` and `Jint_ParsedScript` shows the difference between always parsing the script source file and reusing parsed `Script` instance.

Last updated 2023-11-05
Last updated 2023-11-24

* Jint main
* Jurassic 3.2.7
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<PackageReference Include="MongoDB.Bson.signed" />
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="NodaTime" />
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" />
<PackageReference Include="xunit" />
<PackageReference Include="xunit.runner.visualstudio" />
</ItemGroup>
Expand Down
39 changes: 39 additions & 0 deletions Jint.Tests.PublicInterface/TimeSystemTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Globalization;
using Jint.Runtime;
using Microsoft.Extensions.Time.Testing;
using NodaTime;

namespace Jint.Tests.PublicInterface;
Expand Down Expand Up @@ -33,6 +34,29 @@ public void CanProduceValidDatesUsingNodaTimeIntegration(string input, long expe

Assert.Equal(expected, engine.Evaluate($"new Date({input}) * 1").AsNumber());
}

[Fact]
public void CanUseTimeProvider()
{
var defaultEngine = new Engine();
var defaultNow = DateTimeOffset.Now.ToUnixTimeMilliseconds();
var defaultScriptNow = defaultEngine.Evaluate("new Date() * 1").AsNumber();
Assert.InRange(defaultScriptNow, defaultNow, defaultNow + 100);

var timeProvider = new FakeTimeProvider();
timeProvider.SetUtcNow(new DateTimeOffset(2023, 11, 6, 0, 0, 0, 0, TimeSpan.Zero));

var timeProviderEngine = new Engine(options =>
{
options.TimeSystem = new TimeProviderTimeSystem(timeProvider);
});

var timeProviderNow = timeProvider.GetUtcNow().ToUnixTimeMilliseconds();
var timeProviderScriptNow = timeProviderEngine.Evaluate("new Date() * 1").AsNumber();
Assert.InRange(timeProviderNow, timeProviderScriptNow, timeProviderScriptNow + 100);

Assert.NotInRange(timeProviderScriptNow, defaultScriptNow - 10000, defaultScriptNow + 10000);
}
}

file sealed class NodaTimeSystem : DefaultTimeSystem
Expand All @@ -52,3 +76,18 @@ public override TimeSpan GetUtcOffset(long epochMilliseconds)
return offset.ToTimeSpan();
}
}

file sealed class TimeProviderTimeSystem : DefaultTimeSystem
{
private readonly TimeProvider _timeProvider;

public TimeProviderTimeSystem(TimeProvider timeProvider) : base(TimeZoneInfo.Utc, CultureInfo.CurrentCulture)
{
_timeProvider = timeProvider;
}

public override DateTimeOffset GetUtcNow()
{
return _timeProvider.GetUtcNow();
}
}
6 changes: 5 additions & 1 deletion Jint.Tests.Test262/Test262Harness.settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"SuiteGitSha": "6396ebde0316639292530460d1ef961fd9bbe0d4",
"SuiteGitSha": "2060494f280ba89d71a0f51d4ff171bafe476a05",
//"SuiteDirectory": "//mnt/c/work/test262",
"TargetPath": "./Generated",
"Namespace": "Jint.Tests.Test262",
Expand All @@ -12,6 +12,7 @@
"decorators",
"generators",
"import-assertions",
"import-attributes",
"iterator-helpers",
"regexp-duplicate-named-groups",
"regexp-lookbehind",
Expand Down Expand Up @@ -47,6 +48,7 @@
"built-ins/RegExp/prototype/exec/S15.10.6.2_A1_T6.js",
"language/literals/regexp/u-case-mapping.js",
"built-ins/RegExp/lookahead-quantifier-match-groups.js",
"built-ins/RegExp/unicode_full_case_folding.js",

// requires investigation how to process complex function name evaluation for property
"built-ins/Function/prototype/toString/method-computed-property-name.js",
Expand Down Expand Up @@ -85,6 +87,8 @@
"language/expressions/object/method-definition/name-prop-name-yield-id.js",
"language/statements/class/elements/*-generator-method-*.js",
"language/expressions/class/elements/*-generator-method-*.js",
"built-ins/Set/prototype/union/allows-set-like-class.js",
"built-ins/Set/prototype/union/allows-set-like-object.js",

// generators not implemented
"built-ins/Object/prototype/toString/proxy-function.js",
Expand Down
2 changes: 1 addition & 1 deletion Jint.Tests/Runtime/EngineLimitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class EngineLimitTests
{

#if RELEASE
const int FunctionNestingCount = 840;
const int FunctionNestingCount = 1010;
#else
const int FunctionNestingCount = 510;
#endif
Expand Down
14 changes: 5 additions & 9 deletions Jint/Extensions/Polyfills.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
using System.Runtime.CompilerServices;

namespace Jint;

internal static class Polyfills
{
#if NETFRAMEWORK || NETSTANDARD2_0
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
internal static bool Contains(this string source, char c) => source.IndexOf(c) != -1;

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
internal static bool StartsWith(this string source, char c) => source.Length > 0 && source[0] == c;
#endif

#if NETFRAMEWORK
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
internal static bool Contains(this ReadOnlySpan<string> source, string c) => source.IndexOf(c) != -1;
#endif

#if NETFRAMEWORK || NETSTANDARD2_0
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool StartsWith(this string source, char c) => source.Length > 0 && source[0] == c;
#endif
}
10 changes: 5 additions & 5 deletions Jint/Native/Array/ArrayPrototype.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#pragma warning disable CA1859 // Use concrete types when possible for improved performance -- most of prototype methods return JsValue

using System.Linq;
using System.Text;
using Jint.Collections;
using Jint.Native.Iterator;
using Jint.Native.Number;
using Jint.Native.Object;
using Jint.Native.Symbol;
using Jint.Pooling;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Descriptors.Specialized;
Expand Down Expand Up @@ -1265,15 +1265,15 @@ static string StringFromJsValue(JsValue value)
return s;
}

using var sb = StringBuilderPool.Rent();
sb.Builder.Append(s);
using var sb = new ValueStringBuilder(stackalloc char[256]);
sb.Append(s);
for (uint k = 1; k < len; k++)
{
if (sep != "")
{
sb.Builder.Append(sep);
sb.Append(sep);
}
sb.Builder.Append(StringFromJsValue(o.Get(k)));
sb.Append(StringFromJsValue(o.Get(k)));
}

return sb.ToString();
Expand Down
20 changes: 11 additions & 9 deletions Jint/Native/BigInt/BigIntPrototype.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System.Globalization;
using System.Numerics;
using System.Text;
using Jint.Collections;
using Jint.Native.Object;
using Jint.Native.Symbol;
using Jint.Pooling;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Interop;
Expand Down Expand Up @@ -114,22 +114,24 @@ private JsValue ToBigIntString(JsValue thisObject, JsValue[] arguments)
value = -value;
}

const string digits = "0123456789abcdefghijklmnopqrstuvwxyz";
const string Digits = "0123456789abcdefghijklmnopqrstuvwxyz";

using var builder = StringBuilderPool.Rent();
var sb = builder.Builder;
var sb = new ValueStringBuilder(stackalloc char[64]);

for (; value > 0; value /= radixMV)
{
var d = (int) (value % radixMV);
sb.Append(digits[d]);
sb.Append(Digits[d]);
}

var charArray = new char[sb.Length];
sb.CopyTo(0, charArray, 0, charArray.Length);
System.Array.Reverse(charArray);
if (negative)
{
sb.Append('-');
}

sb.Reverse();

return (negative ? "-" : "") + new string(charArray);
return sb.ToString();
}

/// <summary>
Expand Down
6 changes: 3 additions & 3 deletions Jint/Native/Date/DateConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,9 @@ private static JsValue Utc(JsValue thisObject, JsValue[] arguments)
return finalDate.TimeClip().ToJsValue();
}

private static JsValue Now(JsValue thisObject, JsValue[] arguments)
private JsValue Now(JsValue thisObject, JsValue[] arguments)
{
return (long) (DateTime.UtcNow - Epoch).TotalMilliseconds;
return (long) (_timeSystem.GetUtcNow().DateTime - Epoch).TotalMilliseconds;
}

protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
Expand All @@ -120,7 +120,7 @@ public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
newTarget,
static intrinsics => intrinsics.Date.PrototypeObject,
static (engine, _, dateValue) => new JsDate(engine, dateValue),
(DateTime.UtcNow - Epoch).TotalMilliseconds);
(_timeSystem.GetUtcNow().DateTime - Epoch).TotalMilliseconds);
}

return ConstructUnlikely(arguments, newTarget);
Expand Down
13 changes: 12 additions & 1 deletion Jint/Native/JsValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,18 @@ internal IteratorInstance GetIterator(Realm realm, GeneratorKind hint = Generato
}

[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal IteratorInstance GetIteratorFromMethod(Realm realm, ICallable method)
{
var iterator = method.Call(this);
if (iterator is not ObjectInstance objectInstance)
{
ExceptionHelper.ThrowTypeError(realm);
return null!;
}
return new IteratorInstance.ObjectIterator(objectInstance);
}

[Pure]
internal bool TryGetIterator(Realm realm, [NotNullWhen(true)] out IteratorInstance? iterator, GeneratorKind hint = GeneratorKind.Sync, ICallable? method = null)
{
var obj = TypeConverter.ToObject(realm, this);
Expand Down
34 changes: 8 additions & 26 deletions Jint/Native/Json/JsonParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
using System.Runtime.InteropServices;
using System.Text;
using Esprima;
using Jint.Native.Object;
using Jint.Pooling;
using Jint.Runtime;

namespace Jint.Native.Json
Expand Down Expand Up @@ -172,9 +170,9 @@ private string ScanPunctuatorValue(int start, char code)
}
}

private Token ScanNumericLiteral(ref State state)
private Token ScanNumericLiteral()
{
var sb = state.TokenBuffer;
using var sb = new ValueStringBuilder(stackalloc char[64]);
var start = _index;
var ch = _source.CharCodeAt(_index);
var canBeInteger = true;
Expand Down Expand Up @@ -249,7 +247,6 @@ private Token ScanNumericLiteral(ref State state)
}

var number = sb.ToString();
sb.Clear();

JsNumber value;
if (canBeInteger && long.TryParse(number, NumberStyles.Integer, CultureInfo.InvariantCulture, out var longResult) && longResult != -0)
Expand Down Expand Up @@ -312,7 +309,7 @@ private Token ScanStringLiteral(ref State state)
int start = _index;
++_index;

var sb = state.TokenBuffer;
using var sb = new ValueStringBuilder(stackalloc char[64]);
while (_index < _length)
{
char ch = _source[_index++];
Expand Down Expand Up @@ -382,8 +379,7 @@ private Token ScanStringLiteral(ref State state)
ThrowError(_index, Messages.UnexpectedEOS);
}

string value = sb.ToString();
sb.Clear();
var value = sb.ToString();
return CreateToken(Tokens.String, value, '\"', new JsString(value), new TextRange(start, _index));
}

Expand All @@ -407,14 +403,14 @@ private Token Advance(ref State state)
{
if (IsDecimalDigit(_source.CharCodeAt(_index + 1)))
{
return ScanNumericLiteral(ref state);
return ScanNumericLiteral();
}
return ScanPunctuator();
}

if (IsDecimalDigit(ch))
{
return ScanNumericLiteral(ref state);
return ScanNumericLiteral();
}

if (ch == 't' || ch == 'f')
Expand Down Expand Up @@ -704,8 +700,7 @@ public JsValue Parse(string code, ParserOptions? options)
_length = _source.Length;
_lookahead = null!;

using var wrapper = StringBuilderPool.Rent();
State state = new State(wrapper.Builder);
State state = new State();

Peek(ref state);
JsValue jsv = ParseJsonValue(ref state);
Expand All @@ -719,22 +714,9 @@ public JsValue Parse(string code, ParserOptions? options)
return jsv;
}

[StructLayout(LayoutKind.Auto)]
private ref struct State
{
public State(StringBuilder tokenBuffer)
{
TokenBuffer = tokenBuffer;
CurrentDepth = 0;
}

/// <summary>
/// StringBuilder instance which can be used to collect
/// characters into a single string. Must only be used
/// when no child-parser gets called. Must be cleared
/// after usage.
/// </summary>
public StringBuilder TokenBuffer { get; }

/// <summary>
/// The current recursion depth
/// </summary>
Expand Down
Loading

0 comments on commit 72014dc

Please sign in to comment.