Skip to content

Commit

Permalink
Enable top-level await tests and fix issues (#1552)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed May 14, 2023
1 parent 3f376c7 commit 48c2992
Show file tree
Hide file tree
Showing 17 changed files with 99 additions and 110 deletions.
65 changes: 10 additions & 55 deletions Jint.Tests.Test262/Test262Harness.settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
"resizable-arraybuffer",
"SharedArrayBuffer",
"tail-call-optimization",
"top-level-await",
"Temporal",
"u180e"
],
Expand Down Expand Up @@ -123,42 +122,24 @@
"language/expressions/dynamic-import/assignment-expression/yield-expr.js",
"language/statements/class/subclass/builtin-objects/GeneratorFunction/*.js",
"language/**/*-yield-*.js",
"language/module-code/instn-local-bndng-gen.js",
"language/module-code/instn-local-bndng-export-gen.js",

// JavaScriptParser cannot handle direct 'super.property' script code
"language/expressions/super/prop-dot-cls-val-from-eval.js",
"language/expressions/super/prop-dot-obj-val-from-eval.js",
"language/expressions/super/prop-expr-cls-val-from-eval.js",
"language/expressions/super/prop-expr-obj-val-from-eval.js",

// Esprima problem

"language/literals/regexp/u-surrogate-pairs-atom-escape-decimal.js",
"language/literals/regexp/u-unicode-esc.js",
"language/statements/class/definition/methods-async-super-call-param.js",
"built-ins/AsyncFunction/AsyncFunction-construct.js\n",
"built-ins/String/prototype/split/separator-regexp.js",


"language/expressions/object/method-definition/async-super-call-param.js",
"language/expressions/object/method-definition/name-super-prop-param.js",
"language/expressions/optional-chaining/member-expression.js",
"language/expressions/tagged-template/invalid-escape-sequences.js",
"language/statements/for-of/dstr-obj-id-init-let.js",
"language/statements/for/head-lhs-let.js",
"language/expressions/object/yield-non-strict-access.js",
"language/expressions/object/yield-non-strict-syntax.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/assignment/dstr-obj-id-identifier-yield-ident-valid.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/white-space/mongolian-vowel-separator-eval.js",
"language/statements/for/head-lhs-let.js",

// SharedArrayBuffer not implemented
"built-ins/SharedArrayBuffer/prototype/prop-desc.js",

// Esprima has parsing problems with weirdish unicode identifiers
"language/identifiers/*-unicode-*.js",

// special casing data
"built-ins/**/special_casing*.js",

Expand Down Expand Up @@ -366,32 +347,6 @@
"language/literals/string/line-separator.js",
"language/literals/string/paragraph-separator-eval.js",
"language/literals/string/paragraph-separator.js",
"language/module-code/eval-self-once.js",
"language/module-code/export-expname-binding-index.js",
"language/module-code/instn-iee-bndng-cls.js",
"language/module-code/instn-iee-bndng-const.js",
"language/module-code/instn-iee-bndng-fun.js",
"language/module-code/instn-iee-bndng-let.js",
"language/module-code/instn-iee-bndng-var.js",
"language/module-code/instn-local-bndng-export-gen.js",
"language/module-code/instn-local-bndng-gen.js",
"language/module-code/instn-named-bndng-cls.js",
"language/module-code/instn-named-bndng-const.js",
"language/module-code/instn-named-bndng-dflt-cls.js",
"language/module-code/instn-named-bndng-dflt-expr.js",
"language/module-code/instn-named-bndng-dflt-fun-anon.js",
"language/module-code/instn-named-bndng-dflt-named.js",
"language/module-code/instn-named-bndng-dflt-star.js",
"language/module-code/instn-named-bndng-let.js",
"language/module-code/instn-named-bndng-trlng-comma.js",
"language/module-code/instn-named-bndng-var.js",
"language/module-code/namespace/internals/delete-exported-uninit.js",
"language/module-code/namespace/internals/enumerate-binding-uninit.js",
"language/module-code/namespace/internals/get-own-property-str-found-uninit.js",
"language/module-code/namespace/internals/get-str-found-uninit.js",
"language/module-code/namespace/internals/object-hasOwnProperty-binding-uninit.js",
"language/module-code/namespace/internals/object-keys-binding-uninit.js",
"language/module-code/namespace/internals/object-propertyIsEnumerable-binding-uninit.js",
"language/statementList/eval-block-with-statment-block.js",
"language/statements/for-of/dstr/array-elem-put-obj-literal-prop-ref-init-active.js",
"language/statements/for-of/dstr/array-elem-put-obj-literal-prop-ref-init.js",
Expand Down
5 changes: 3 additions & 2 deletions Jint.Tests.Test262/Test262Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ private static void ExecuteTest(Engine engine, Test262File file)
{
if (file.Type == ProgramType.Module)
{
engine.AddModule(file.FileName, builder => builder.AddSource(file.Program));
engine.ImportModule(file.FileName);
var specifier = "./" + Path.GetFileName(file.FileName);
engine.AddModule(specifier, builder => builder.AddSource(file.Program));
engine.ImportModule(specifier);
}
else
{
Expand Down
1 change: 0 additions & 1 deletion Jint.Tests/Runtime/ModuleTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ public void ShouldImportDynamically()
_engine.AddModule("my-module", @"import('imported-module').then(ns => { ns.signal(); });");

_engine.ImportModule("my-module");
_engine.RunAvailableContinuations();

Assert.True(received);
}
Expand Down
6 changes: 3 additions & 3 deletions Jint/Engine.Modules.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,14 @@ private static void LinkModule(string specifier, ModuleRecord module)
module.Link();
}

private JsValue EvaluateModule(string specifier, ModuleRecord cyclicModule)
private JsValue EvaluateModule(string specifier, ModuleRecord module)
{
var ownsContext = _activeEvaluationContext is null;
_activeEvaluationContext ??= new EvaluationContext(this);
JsValue evaluationResult;
try
{
evaluationResult = cyclicModule.Evaluate();
evaluationResult = module.Evaluate();
}
finally
{
Expand All @@ -154,7 +154,7 @@ private JsValue EvaluateModule(string specifier, ModuleRecord cyclicModule)
}
else if (promise.State == PromiseState.Rejected)
{
var location = cyclicModule is CyclicModuleRecord cyclicModuleRecord
var location = module is CyclicModuleRecord cyclicModuleRecord
? cyclicModuleRecord.AbnormalCompletionLocation
: Location.From(new Position(), new Position());

Expand Down
15 changes: 12 additions & 3 deletions Jint/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -404,12 +404,12 @@ private Engine ScriptEvaluation(ScriptRecord scriptRecord)
throw ex;
}

_completionValue = result.GetValueOrDefault();

// TODO what about callstack and thrown exceptions?
RunAvailableContinuations();

_completionValue = result.GetValueOrDefault();

return this;
return this;
}
finally
{
Expand Down Expand Up @@ -459,7 +459,16 @@ internal void AddToKeptObjects(JsValue target)
internal void RunAvailableContinuations()
{
var queue = _eventLoop.Events;
if (queue.Count == 0)
{
return;
}

DoProcessEventLoop(queue);
}

private static void DoProcessEventLoop(Queue<Action> queue)
{
while (true)
{
if (queue.Count == 0)
Expand Down
12 changes: 1 addition & 11 deletions Jint/EsprimaExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -438,17 +438,7 @@ private static List<string> GetExportNames(StatementListItem declaration)

break;
case VariableDeclaration variableDeclaration:
ref readonly var declarators = ref variableDeclaration.Declarations;
for (var i = 0; i < declarators.Count; i++)
{
var declarator = declarators[i];
var varName = declarator.Id.As<Identifier>()?.Name;
if (varName is not null)
{
result.Add(varName);
}
}

variableDeclaration.GetBoundNames(result);
break;
}

Expand Down
4 changes: 1 addition & 3 deletions Jint/HoistingScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,7 @@ internal void Visit(Node node)
var import = (ImportDeclaration) childNode;
import.GetImportEntries(_importEntries, _requestedModules);
}
else if (childNode.Type == Nodes.ExportAllDeclaration ||
childNode.Type == Nodes.ExportDefaultDeclaration ||
childNode.Type == Nodes.ExportNamedDeclaration)
else if (childNode.Type is Nodes.ExportAllDeclaration or Nodes.ExportDefaultDeclaration or Nodes.ExportNamedDeclaration)
{
_exportEntries ??= new();
_requestedModules ??= new();
Expand Down
26 changes: 15 additions & 11 deletions Jint/Native/Promise/PromiseConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,9 @@ public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
return promise;
}

// The abstract operation PromiseResolve takes arguments C (a constructor) and x (an ECMAScript language value).
// It returns a new promise resolved with x. It performs the following steps when called:
//
// 1. Assert: Type(C) is Object.
// 2. If IsPromise(x) is true, then
// a. Let xConstructor be ? Get(x, "constructor").
// b. If SameValue(xConstructor, C) is true, return x.
// 3. Let promiseCapability be ? NewPromiseCapability(C).
// 4. Perform ? Call(promiseCapability.[[Resolve]], undefined, « x »).
// 5. Return promiseCapability.[[Promise]].
/// <summary>
/// https://tc39.es/ecma262/#sec-promise.resolve
/// </summary>
internal JsValue Resolve(JsValue thisObj, JsValue[] arguments)
{
if (!thisObj.IsObject())
Expand All @@ -116,7 +109,15 @@ internal JsValue Resolve(JsValue thisObj, JsValue[] arguments)
ExceptionHelper.ThrowTypeError(_realm, "Promise.resolve invoked on a non-constructor value");
}

JsValue x = arguments.At(0);
var x = arguments.At(0);
return PromiseResolve(thisObj, x);
}

/// <summary>
/// https://tc39.es/ecma262/#sec-promise-resolve
/// </summary>
private JsValue PromiseResolve(JsValue thisObj, JsValue x)
{
if (x.IsPromise())
{
var xConstructor = x.Get(CommonProperties.Constructor);
Expand All @@ -133,6 +134,9 @@ internal JsValue Resolve(JsValue thisObj, JsValue[] arguments)
return instance;
}

/// <summary>
/// https://tc39.es/ecma262/#sec-promise.reject
/// </summary>
private JsValue Reject(JsValue thisObj, JsValue[] arguments)
{
if (!thisObj.IsObject())
Expand Down
13 changes: 9 additions & 4 deletions Jint/Native/Promise/PromiseInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,13 @@ internal ResolvingFunctions CreateResolvingFunctions()
// https://tc39.es/ecma262/#sec-promise-resolve-functions
private JsValue Resolve(JsValue thisObj, JsValue[] arguments)
{
// Note that alreadyResolved logic lives in CreateResolvingFunctions method

var result = arguments.At(0);
return Resolve(result);
}

internal JsValue Resolve(JsValue result)
{
// Note that alreadyResolved logic lives in CreateResolvingFunctions method

if (ReferenceEquals(result, this))
{
Expand All @@ -114,8 +118,9 @@ private JsValue Resolve(JsValue thisObj, JsValue[] arguments)
return FulfillPromise(result);
}

_engine.AddToEventLoop(
PromiseOperations.NewPromiseResolveThenableJob(this, resultObj, thenMethod));
var realm = _engine.Realm;
var job = PromiseOperations.NewPromiseResolveThenableJob(this, resultObj, thenMethod);
_engine._host.HostEnqueuePromiseJob(job, realm);

return Undefined;
}
Expand Down
6 changes: 3 additions & 3 deletions Jint/Native/ShadowRealm/ShadowRealm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ public JsValue Evaluate(string sourceText)
public JsValue ImportValue(string specifier, string exportName)
{
var callerRealm = _engine.Realm;
return ShadowRealmImportValue(specifier, exportName, callerRealm);
var value = ShadowRealmImportValue(specifier, exportName, callerRealm);
_engine.RunAvailableContinuations();
return value;
}

/// <summary>
Expand Down Expand Up @@ -210,8 +212,6 @@ private static void CopyNameAndLength(WrappedFunction f, ObjectInstance target,
var promiseCapability = PromiseConstructor.NewPromiseCapability(_engine, _engine.Realm.Intrinsics.Promise);
var value = PromiseOperations.PerformPromiseThen(_engine, (PromiseInstance) innerCapability.PromiseInstance, onFulfilled, callerRealm.Intrinsics.ThrowTypeError, promiseCapability);

_engine.RunAvailableContinuations();

return value;
}

Expand Down
8 changes: 8 additions & 0 deletions Jint/Runtime/Host.cs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,14 @@ internal virtual JobCallback MakeJobCallBack(ICallable cleanupCallback)
{
return new JobCallback(cleanupCallback, null);
}

/// <summary>
/// https://tc39.es/ecma262/#sec-hostenqueuepromisejob
/// </summary>
internal void HostEnqueuePromiseJob(Action job, Realm realm)
{
Engine.AddToEventLoop(job);
}
}
}

Expand Down
11 changes: 11 additions & 0 deletions Jint/Runtime/Interpreter/Expressions/JintAwaitExpression.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Esprima.Ast;
using Jint.Native;
using Jint.Native.Object;
using Jint.Native.Promise;

namespace Jint.Runtime.Interpreter.Expressions;

Expand All @@ -24,6 +27,14 @@ protected override object EvaluateInternal(EvaluationContext context)
try
{
var value = _awaitExpression.GetValue(context);

if (value is not PromiseInstance)
{
var promiseInstance = new PromiseInstance(engine);
promiseInstance.Resolve(value);
value = promiseInstance;
}

engine.RunAvailableContinuations();
return value.UnwrapIfPromise();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ protected override object EvaluateInternal(EvaluationContext context)
}

context.Engine._host.ImportModuleDynamically(referencingScriptOrModule, specifierString, promiseCapability);
context.Engine.RunAvailableContinuations();
return promiseCapability.PromiseInstance;
}
}
14 changes: 9 additions & 5 deletions Jint/Runtime/Interpreter/Statements/JintForInForOfStatement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,17 @@ private bool HeadEvaluation(EvaluationContext context, [NotNullWhen(true)] out I
close = true;
status = context.Completion;
}
else if (lhsKind == LhsKind.LexicalBinding)
{
((Reference) lhsRef).InitializeReferencedBinding(nextValue);
}
else
{
engine.PutValue((Reference) lhsRef, nextValue);
var reference = (Reference) lhsRef;
if (lhsKind == LhsKind.LexicalBinding || _leftNode.Type == Nodes.Identifier && !reference.IsUnresolvableReference)
{
reference.InitializeReferencedBinding(nextValue);
}
else
{
engine.PutValue(reference, nextValue);
}
}
}
else
Expand Down
4 changes: 2 additions & 2 deletions Jint/Runtime/Modules/CyclicModuleRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public override JsValue Evaluate()
module._topLevelCapability = capability;

var result = module.InnerModuleEvaluation(stack, 0, ref asyncEvalOrder);

if (result.Type != CompletionType.Normal)
{
foreach (var m in stack)
Expand Down Expand Up @@ -389,7 +389,7 @@ protected internal override Completion InnerModuleEvaluation(Stack<CyclicModuleR
requiredModule.Status = ModuleStatus.EvaluatingAsync;
}

done = requiredModule == this;
done = ReferenceEquals(requiredModule, this);
requiredModule._cycleRoot = this;
}
}
Expand Down

0 comments on commit 48c2992

Please sign in to comment.