Skip to content

Commit

Permalink
Merge branch 'sebastienros:main' into feature/task-promise-conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
Xicy authored Aug 21, 2023
2 parents 2bc575d + f4982ee commit 8965b51
Show file tree
Hide file tree
Showing 125 changed files with 2,050 additions and 1,283 deletions.
2 changes: 1 addition & 1 deletion Jint.Benchmark/DromaeoBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class DromaeoBenchmark
{"dromaeo-string-base64", null}
};

private Dictionary<string, Script> _prepared = new();
private readonly Dictionary<string, Script> _prepared = new();

private Engine engine;

Expand Down
2 changes: 1 addition & 1 deletion Jint.Benchmark/EngineConstructionBenchmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ public double BuildEngine()
var engine = new Engine();
return engine.Evaluate(_program).AsNumber();
}
}
}
22 changes: 10 additions & 12 deletions Jint.Repl/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private static void Main(string[] args)
var parserOptions = new ParserOptions
{
Tolerant = true,
AdaptRegexp = true
RegExpParseMode = RegExpParseMode.AdaptToInterpreted
};

var serializer = new JsonSerializer(engine);
Expand All @@ -66,22 +66,20 @@ private static void Main(string[] args)
try
{
var result = engine.Evaluate(input, parserOptions);
JsValue str = result;
if (!result.IsPrimitive() && result is not IPrimitiveInstance)
{
var str = serializer.Serialize(result, JsValue.Undefined, " ");
Console.WriteLine(str);
}
else
{
if (result.IsString())
{
Console.WriteLine(serializer.Serialize(result, JsValue.Undefined, JsValue.Undefined));
}
else
str = serializer.Serialize(result, JsValue.Undefined, " ");
if (str == JsValue.Undefined)
{
Console.WriteLine(result);
str = result;
}
}
else if (result.IsString())
{
str = serializer.Serialize(result, JsValue.Undefined, JsValue.Undefined);
}
Console.WriteLine(str);
}
catch (JavaScriptException je)
{
Expand Down
57 changes: 13 additions & 44 deletions Jint.Tests.Test262/Test262Harness.settings.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
{
"SuiteGitSha": "9704d7f22f6342d6c4753ab9a8d62d6725de8c4e",
"SuiteGitSha": "9437cab774ab2f22c5cb971b11b8512eca705721",
//"SuiteDirectory": "//mnt/c/work/test262",
"TargetPath": "./Generated",
"Namespace": "Jint.Tests.Test262",
"Parallel": true,
"ExcludedFeatures": [
"Array.fromAsync",
"arraybuffer-transfer",
"async-iteration",
"Atomics",
"decorators",
"generators",
"import-assertions",
"iterator-helpers",
"regexp-duplicate-named-groups",
"regexp-lookbehind",
"regexp-unicode-property-escapes",
Expand All @@ -28,45 +30,22 @@
"intl402"
],
"ExcludedFiles": [
// Esprima problem for regex, https://github.com/sebastienros/esprima-dotnet/pull/364
"built-ins/RegExp/S15.10.4.1_A9_T3.js",

// Currently quite impossible to detect if assignment target is CoverParenthesizedExpression
"language/expressions/assignment/fn-name-lhs-cover.js",

// Unicode support not built-in to .NET the same way, requires more work
"built-ins/RegExp/prototype/Symbol.match/builtin-infer-unicode.js",
"built-ins/RegExp/prototype/Symbol.search/u-lastindex-advance.js",
"built-ins/RegExp/prototype/exec/u-lastindex-adv.js",
"built-ins/RegExp/unicode_character_class_backspace_escape.js",
"built-ins/RegExp/unicode_restricted_identity_escape_alpha.js",
"built-ins/RegExp/unicode_restricted_identity_escape_c.js",
"built-ins/RegExp/unicode_restricted_identity_escape_u.js",
"built-ins/RegExp/unicode_restricted_identity_escape_x.js",
"language/literals/regexp/u-astral-char-class-invert.js",
"language/literals/regexp/u-astral.js",
"language/literals/regexp/u-case-mapping.js",

// cannot have characters like 𝒜 as group name or something starting with $ in .NET, other .NET limitations
"built-ins/RegExp/match-indices/indices-array-unicode-property-names.js",
"built-ins/RegExp/named-groups/non-unicode-match.js",
"built-ins/RegExp/named-groups/non-unicode-property-names-valid.js",
"built-ins/RegExp/named-groups/non-unicode-property-names.js",
"built-ins/RegExp/named-groups/unicode-match.js",
"built-ins/RegExp/named-groups/unicode-property-names-valid.js",
"built-ins/RegExp/named-groups/unicode-property-names.js",
"built-ins/RegExp/prototype/Symbol.replace/named-groups.js",
// RegExp conversion limitations
"built-ins/RegExp/S15.10.2.11_A1_T5.js",
"built-ins/RegExp/S15.10.2.11_A1_T7.js",
"built-ins/RegExp/S15.10.2.5_A1_T4.js",
"built-ins/RegExp/named-groups/non-unicode-references.js",
"built-ins/RegExp/named-groups/unicode-references.js",
"built-ins/RegExp/quantifier-integer-limit.js",
"language/literals/regexp/named-groups/forward-reference.js",

// more validation and cleanup needed
"built-ins/RegExp/S15.10.2.13_A1_T1.js",
"built-ins/RegExp/S15.10.2.13_A1_T2.js",
"built-ins/RegExp/character-class-escape-non-whitespace.js",
"built-ins/RegExp/unicode_character_class_backspace_escape.js",
"built-ins/RegExp/unicode_identity_escape.js",
"built-ins/RegExp/unicode_restricted_character_class_escape.js",
"built-ins/RegExp/unicode_restricted_identity_escape.js",
"built-ins/RegExp/unicode_restricted_quantifiable_assertion.js",
// RegExp handling problems
"built-ins/RegExp/prototype/exec/S15.10.6.2_A1_T6.js",
"language/literals/regexp/u-case-mapping.js",

// requires investigation how to process complex function name evaluation for property
"built-ins/Function/prototype/toString/method-computed-property-name.js",
Expand All @@ -75,13 +54,6 @@
// http://www.ecma-international.org/ecma-262/#sec-block-level-function-declarations-web-legacy-compatibility-semantics not implemented (block level functions)
"language/statements/let/block-local-closure-set-before-initialization.js",

// Logic difference in .NET RegExp / skipped in ECMA tests too
"built-ins/RegExp/S15.10.2.11_A1_T5.js",
"built-ins/RegExp/S15.10.2.11_A1_T7.js",
"built-ins/RegExp/S15.10.4.1_A8_T2.js",
"built-ins/RegExp/prototype/exec/S15.10.6.2_A1_T6.js",
"built-ins/RegExp/S15.10.2.5_A1_T4.js",

// Windows line ending differences
"built-ins/String/raw/special-characters.js",

Expand Down Expand Up @@ -126,14 +98,11 @@
"language/module-code/instn-local-bndng-export-gen.js",

// Esprima problem
"built-ins/String/prototype/split/separator-regexp.js",
"language/expressions/object/let-non-strict-access.js",
"language/expressions/object/let-non-strict-syntax.js",
"language/expressions/object/yield-non-strict-access.js",
"language/expressions/object/yield-non-strict-syntax.js",
"language/expressions/tagged-template/invalid-escape-sequences.js",
"language/literals/regexp/u-surrogate-pairs-atom-escape-decimal.js",
"language/literals/regexp/u-unicode-esc.js",
"language/statements/for-of/dstr-obj-id-identifier-yield-ident-valid.js",
"language/statements/for/head-lhs-let.js",

Expand Down
2 changes: 1 addition & 1 deletion Jint.Tests.Test262/Test262ModuleLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public Module LoadModule(Engine engine, ResolvedSpecifier resolved)

var parserOptions = new ParserOptions
{
AdaptRegexp = true,
RegExpParseMode = RegExpParseMode.AdaptToInterpreted,
Tolerant = true
};

Expand Down
4 changes: 2 additions & 2 deletions Jint.Tests.Test262/Test262Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ private Engine BuildTestExecutor(Test262File file)
throw new Exception("only script parsing supported");
}
var options = new ParserOptions { AdaptRegexp = true, Tolerant = false };
var options = new ParserOptions { RegExpParseMode = RegExpParseMode.AdaptToInterpreted, Tolerant = false };
var parser = new JavaScriptParser(options);
var script = parser.ParseScript(args.At(0).AsString());
Expand All @@ -56,7 +56,7 @@ private Engine BuildTestExecutor(Test262File file)
o.FastSetProperty("detachArrayBuffer", new PropertyDescriptor(new ClrFunctionInstance(engine, "detachArrayBuffer",
(_, args) =>
{
var buffer = (ArrayBufferInstance) args.At(0);
var buffer = (JsArrayBuffer) args.At(0);
buffer.DetachArrayBuffer();
return JsValue.Undefined;
}), true, true, true));
Expand Down
35 changes: 33 additions & 2 deletions Jint.Tests/Runtime/ConstructorSignatureTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ public void CorrectOverloadShouldBeSelected()
Assert.Equal("A-30", engine.Evaluate("new B('A', 30).Result"));
}


[Fact]
public void CanConstructWithMixedFloatAndEnumConstructorParameters()
{
var engine = new Engine();
engine.SetValue("Length", TypeReference.CreateTypeReference<Length>(engine));
Assert.Equal(12.3, engine.Evaluate("new Length(12.3).Value").AsNumber(), precision: 2);
Assert.Equal(12.3, engine.Evaluate("new Length(12.3, 0).Value").AsNumber(), precision: 2);
Assert.Equal(0, engine.Evaluate("new Length(12.3, 0).UnitValue").AsInteger());
Assert.Equal(LengthUnit.Pixel, (LengthUnit) engine.Evaluate("new Length(12.3, 42).UnitValue").AsInteger());
}

private class A
{
public A(int param1, int param2 = 5) => Result = (param1 + param2).ToString();
Expand All @@ -62,8 +74,27 @@ public B(string param1, float param2, string param3)
public B(string param1, float param2)
{
Result = string.Join("-", param1, param2.ToString(CultureInfo.InvariantCulture));
}
}

public string Result { get; }
}

private enum LengthUnit { Pixel = 42 }

private class Length
{
public Length(float value)
: this(value, LengthUnit.Pixel)
{
}

public Length(float value, LengthUnit unit)
{
Value = value;
UnitValue = unit;
}

public string Result { get;}
public float Value { get; }
public LengthUnit UnitValue { get; }
}
}
11 changes: 4 additions & 7 deletions Jint.Tests/Runtime/Domain/UuidPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,14 @@ private UuidPrototype(Engine engine) : base(engine)
{
}

private UuidInstance EnsureUuidInstance(JsValue thisObj)
private UuidInstance EnsureUuidInstance(JsValue thisObject)
{
return thisObj.TryCast<UuidInstance>(value =>
{
throw new JavaScriptException(Engine.Realm.Intrinsics.TypeError, "Invalid Uuid");
});
return thisObject.TryCast<UuidInstance>(value => throw new JavaScriptException(Engine.Realm.Intrinsics.TypeError, "Invalid Uuid"));
}

private JsValue ToGuidString(JsValue thisObj, JsValue[] arguments) => EnsureUuidInstance(thisObj).PrimitiveValue.ToString();
private JsValue ToGuidString(JsValue thisObject, JsValue[] arguments) => EnsureUuidInstance(thisObject).PrimitiveValue.ToString();

private JsValue ValueOf(JsValue thisObj, JsValue[] arguments) => EnsureUuidInstance(thisObj).PrimitiveValue;
private JsValue ValueOf(JsValue thisObject, JsValue[] arguments) => EnsureUuidInstance(thisObject).PrimitiveValue;

public static UuidPrototype CreatePrototypeObject(Engine engine, UuidConstructor ctor)
{
Expand Down
70 changes: 56 additions & 14 deletions Jint.Tests/Runtime/EngineLimitTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
#if !NETFRAMEWORK

using System.Text;
using Jint.Runtime;

namespace Jint.Tests.Runtime;

public class EngineLimitTests
{

#if RELEASE
const int FunctionNestingCount = 960;
#else
const int FunctionNestingCount = 520;
#endif

[Fact]
public void ShouldAllowReasonableCallStackDepth()
{
Expand All @@ -15,24 +23,61 @@ public void ShouldAllowReasonableCallStackDepth()
return;
}

#if RELEASE
const int FunctionNestingCount = 960;
#else
const int FunctionNestingCount = 520;
#endif
var script = GenerateCallTree(FunctionNestingCount);

// generate call tree
var engine = new Engine();
engine.Execute(script);
Assert.Equal(123, engine.Evaluate("func1(123);").AsNumber());
Assert.Equal(FunctionNestingCount, engine.Evaluate("x").AsNumber());
}

[Fact]
public void ShouldNotStackoverflowWhenStackGuardEnable()
{
// Can be more than actual dotnet stacktrace count, It does not hit stackoverflow anymore.
int functionNestingCount = FunctionNestingCount * 2;

var script = GenerateCallTree(functionNestingCount);

var engine = new Engine(option => option.Constraints.MaxExecutionStackCount = functionNestingCount);
engine.Execute(script);
Assert.Equal(123, engine.Evaluate("func1(123);").AsNumber());
Assert.Equal(functionNestingCount, engine.Evaluate("x").AsNumber());
}

[Fact]
public void ShouldThrowJavascriptExceptionWhenStackGuardExceed()
{
// Can be more than actual dotnet stacktrace count, It does not hit stackoverflow anymore.
int functionNestingCount = FunctionNestingCount * 2;

var script = GenerateCallTree(functionNestingCount);

var engine = new Engine(option => option.Constraints.MaxExecutionStackCount = 500);
try
{
engine.Execute(script);
engine.Evaluate("func1(123);");
}
catch (JavaScriptException jsException)
{
Assert.Equal("Maximum call stack size exceeded", jsException.Message);
}
}

private string GenerateCallTree(int functionNestingCount)
{
var sb = new StringBuilder();
sb.AppendLine("var x = 10;");
sb.AppendLine("var x = 1;");
sb.AppendLine();
for (var i = 1; i <= FunctionNestingCount; ++i)
for (var i = 1; i <= functionNestingCount; ++i)
{
sb.Append("function func").Append(i).Append("(func").Append(i).AppendLine("Param) {");
sb.Append(" ");
if (i != FunctionNestingCount)
if (i != functionNestingCount)
{
// just to create a bit more nesting add some constructs
sb.Append("return x++ > 1 ? func").Append(i + 1).Append("(func").Append(i).AppendLine("Param): undefined;");
sb.Append("return x++ >= 1 ? func").Append(i + 1).Append("(func").Append(i).AppendLine("Param): undefined;");
}
else
{
Expand All @@ -43,10 +88,7 @@ public void ShouldAllowReasonableCallStackDepth()
sb.AppendLine("}");
sb.AppendLine();
}

var engine = new Engine();
engine.Execute(sb.ToString());
Assert.Equal(123, engine.Evaluate("func1(123);").AsNumber());
return sb.ToString();
}
}

Expand Down
25 changes: 25 additions & 0 deletions Jint.Tests/Runtime/EngineTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1883,6 +1883,31 @@ public void DateShouldParseToString()
");
}


[Fact]
public void ShouldThrowErrorWhenMaxExecutionStackCountLimitExceeded()
{
new Engine(options => options.Constraints.MaxExecutionStackCount = 1000)
.SetValue("assert", new Action<bool>(Assert.True))
.Evaluate(@"
var count = 0;
function recurse() {
count++;
recurse();
return null; // ensure no tail recursion
}
try {
count = 0;
recurse();
assert(false);
} catch(err) {
assert(count >= 1000);
}
");

}


[Fact]
public void LocaleNumberShouldUseLocalCulture()
{
Expand Down
Loading

0 comments on commit 8965b51

Please sign in to comment.