Skip to content

Commit

Permalink
Groundwork for generators (#1705)
Browse files Browse the repository at this point in the history
* basic constructor, prototype and instance,
* update some packages
* remove null value from completion which violates NRT promises
  • Loading branch information
lahma committed Dec 30, 2023
1 parent 93c5ee5 commit 3ab67e4
Show file tree
Hide file tree
Showing 51 changed files with 648 additions and 219 deletions.
16 changes: 8 additions & 8 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,31 @@
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="BenchmarkDotNet" Version="0.13.10" />
<PackageVersion Include="BenchmarkDotNet" Version="0.13.11" />
<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.116" />
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.132" />
<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="NiL.JS" Version="2.5.1677" />
<PackageVersion Include="NodaTime" Version="3.1.9" />
<PackageVersion Include="NUnit" Version="4.0.0" />
<PackageVersion Include="NUnit" Version="4.0.1" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageVersion Include="SharpZipLib" Version="1.4.0" />
<PackageVersion Include="Spectre.Console.Cli" Version="0.45.0" />
<PackageVersion Include="System.Text.Json" Version="6.0.8" />
<PackageVersion Include="Test262Harness" Version="0.0.22" />
<PackageVersion Include="xunit" Version="2.6.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.4" PrivateAssets="all" />
<PackageVersion Include="Test262Harness" Version="0.0.23" />
<PackageVersion Include="xunit" Version="2.6.4" />
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.6" PrivateAssets="all" />
<PackageVersion Include="YantraJS.Core" Version="1.2.206" />
</ItemGroup>
<ItemGroup>
<GlobalPackageReference Include="GitHubActionsTestLogger" Version="2.3.3" />
<GlobalPackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<GlobalPackageReference Include="PolySharp" Version="1.14.0" />
<GlobalPackageReference Include="PolySharp" Version="1.14.1" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Jint.Tests.Test262/.config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"isRoot": true,
"tools": {
"test262harness.console": {
"version": "0.0.22",
"version": "0.0.23",
"commands": [
"test262"
]
Expand Down
4 changes: 2 additions & 2 deletions Jint.Tests/Runtime/EngineLimitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ public class EngineLimitTests
{

#if RELEASE
const int FunctionNestingCount = 1010;
const int FunctionNestingCount = 1000;
#else
const int FunctionNestingCount = 510;
const int FunctionNestingCount = 495;
#endif

[Fact]
Expand Down
16 changes: 14 additions & 2 deletions Jint/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Jint.Native;
using Jint.Native.Argument;
using Jint.Native.Function;
using Jint.Native.Generator;
using Jint.Native.Object;
using Jint.Native.Promise;
using Jint.Native.Symbol;
Expand Down Expand Up @@ -553,7 +554,7 @@ internal JsValue GetValue(Reference reference, bool returnReferenceToPool)
ExceptionHelper.ThrowReferenceError(Realm, reference);
}

if ((baseValue._type & InternalTypes.ObjectEnvironmentRecord) == InternalTypes.None
if ((baseValue._type & InternalTypes.ObjectEnvironmentRecord) == InternalTypes.Empty
&& _referenceResolver.TryPropertyReference(this, reference, ref baseValue))
{
return baseValue;
Expand Down Expand Up @@ -584,7 +585,7 @@ internal JsValue GetValue(Reference reference, bool returnReferenceToPool)
// check if we are accessing a string, boxing operation can be costly to do index access
// we have good chance to have fast path with integer or string indexer
ObjectInstance? o = null;
if ((property._type & (InternalTypes.String | InternalTypes.Integer)) != InternalTypes.None
if ((property._type & (InternalTypes.String | InternalTypes.Integer)) != InternalTypes.Empty
&& baseValue is JsString s
&& TryHandleStringValue(property, s, ref o, out var jsValue))
{
Expand Down Expand Up @@ -1370,6 +1371,12 @@ internal void UpdatePrivateEnvironment(PrivateEnvironmentRecord? newEnv)
_executionContexts.ReplaceTopPrivateEnvironment(newEnv);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ref readonly ExecutionContext UpdateGenerator(GeneratorInstance generator)
{
return ref _executionContexts.ReplaceTopGenerator(generator);
}

/// <summary>
/// Invokes the named callable and returns the resulting object.
/// </summary>
Expand Down Expand Up @@ -1547,6 +1554,11 @@ internal void RegisterTypeReference(TypeReference reference)
_typeReferences[reference.ReferenceType] = reference;
}

internal ref readonly ExecutionContext GetExecutionContext(int fromTop)
{
return ref _executionContexts.Peek(fromTop);
}

public void Dispose()
{
if (_objectWrapperCache is null)
Expand Down
10 changes: 5 additions & 5 deletions Jint/JsValueExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static class JsValueExtensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsPrimitive(this JsValue value)
{
return (value._type & (InternalTypes.Primitive | InternalTypes.Undefined | InternalTypes.Null)) != InternalTypes.None;
return (value._type & (InternalTypes.Primitive | InternalTypes.Undefined | InternalTypes.Null)) != InternalTypes.Empty;
}

[Pure]
Expand Down Expand Up @@ -76,28 +76,28 @@ public static bool IsRegExp(this JsValue value)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsObject(this JsValue value)
{
return (value._type & InternalTypes.Object) != InternalTypes.None;
return (value._type & InternalTypes.Object) != InternalTypes.Empty;
}

[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsString(this JsValue value)
{
return (value._type & InternalTypes.String) != InternalTypes.None;
return (value._type & InternalTypes.String) != InternalTypes.Empty;
}

[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNumber(this JsValue value)
{
return (value._type & (InternalTypes.Number | InternalTypes.Integer)) != InternalTypes.None;
return (value._type & (InternalTypes.Number | InternalTypes.Integer)) != InternalTypes.Empty;
}

[Pure]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsBigInt(this JsValue value)
{
return (value._type & InternalTypes.BigInt) != InternalTypes.None;
return (value._type & InternalTypes.BigInt) != InternalTypes.Empty;
}

[Pure]
Expand Down
4 changes: 2 additions & 2 deletions Jint/Native/Array/ArrayInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -314,9 +314,9 @@ protected sealed override bool TryGetProperty(JsValue property, [NotNullWhen(tru
return base.TryGetProperty(property, out descriptor);
}

public sealed override List<JsValue> GetOwnPropertyKeys(Types types = Types.None | Types.String | Types.Symbol)
public sealed override List<JsValue> GetOwnPropertyKeys(Types types = Types.Empty | Types.String | Types.Symbol)
{
if ((types & Types.String) == Types.None)
if ((types & Types.String) == Types.Empty)
{
return base.GetOwnPropertyKeys(types);
}
Expand Down
4 changes: 2 additions & 2 deletions Jint/Native/Array/ArrayOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public static ArrayOperations For(Realm realm, JsValue thisObj)
for (uint i = 0; i < (uint) jsValues.Length; i++)
{
var jsValue = skipHoles && !HasProperty(i) ? JsValue.Undefined : Get(i);
if ((jsValue.Type & elementTypes) == Types.None)
if ((jsValue.Type & elementTypes) == Types.Empty)
{
ExceptionHelper.ThrowTypeErrorNoEngine("invalid type");
}
Expand Down Expand Up @@ -251,7 +251,7 @@ public override JsValue[] GetAll(Types elementTypes = Types.Undefined | Types.Nu
value = _target.Prototype?.Get(i) ?? JsValue.Undefined;
}

if ((value.Type & elementTypes) == Types.None)
if ((value.Type & elementTypes) == Types.Empty)
{
ExceptionHelper.ThrowTypeErrorNoEngine("invalid type");
}
Expand Down
2 changes: 1 addition & 1 deletion Jint/Native/Date/DatePrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ private JsValue ToPrimitive(JsValue thisObject, JsValue[] arguments)
}

var hintString = hint.ToString();
var tryFirst = Types.None;
var tryFirst = Types.Empty;
if (string.Equals(hintString, "default", StringComparison.Ordinal) || string.Equals(hintString, "string", StringComparison.Ordinal))
{
tryFirst = Types.String;
Expand Down
70 changes: 41 additions & 29 deletions Jint/Native/Function/ClassDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ public JsValue BuildConstructor(EvaluationContext context, EnvironmentRecord env
}
else
{
var temp = superclass.Get("prototype");
var temp = superclass.Get(CommonProperties.Prototype);
if (temp is ObjectInstance protoParentObject)
{
protoParent = protoParentObject;
Expand Down Expand Up @@ -342,25 +342,25 @@ public ClassStaticBlockFunction(StaticBlock staticBlock) : base(Nodes.StaticBloc
/// <summary>
/// https://tc39.es/ecma262/#sec-runtime-semantics-methoddefinitionevaluation
/// </summary>
private static PrivateElement? MethodDefinitionEvaluation(
internal static PrivateElement? MethodDefinitionEvaluation<T>(
Engine engine,
ObjectInstance obj,
MethodDefinition method,
bool enumerable)
T method,
bool enumerable) where T : IProperty
{
if (method.Kind != PropertyKind.Get && method.Kind != PropertyKind.Set)
{
var methodDef = method.DefineMethod(obj);
methodDef.Closure.SetFunctionName(methodDef.Key);
return DefineMethodProperty(obj, methodDef.Key, methodDef.Closure, enumerable);
}

var function = method.Value as IFunction;
if (function is null)
{
ExceptionHelper.ThrowSyntaxError(obj.Engine.Realm);
}

if (method.Kind != PropertyKind.Get && method.Kind != PropertyKind.Set && !function.Generator)
{
var methodDef = method.DefineMethod(obj);
methodDef.Closure.SetFunctionName(methodDef.Key);
return DefineMethodProperty(obj, methodDef.Key, methodDef.Closure, enumerable);
}

var getter = method.Kind == PropertyKind.Get;

var definition = new JintFunctionDefinition(function);
Expand All @@ -371,27 +371,39 @@ public ClassStaticBlockFunction(StaticBlock staticBlock) : base(Nodes.StaticBloc
var env = engine.ExecutionContext.LexicalEnvironment;
var privateEnv = engine.ExecutionContext.PrivateEnvironment;

var closure = intrinsics.Function.OrdinaryFunctionCreate(intrinsics.Function.PrototypeObject, definition, definition.ThisMode, env, privateEnv);
closure.MakeMethod(obj);
closure.SetFunctionName(propKey, getter ? "get" : "set");

if (method.Key is PrivateIdentifier privateIdentifier)
if (function.Generator)
{
return new PrivateElement
{
Key = privateEnv!.Names[privateIdentifier],
Kind = PrivateElementKind.Accessor,
Get = getter ? closure : null,
Set = !getter ? closure : null
};
var closure = intrinsics.Function.OrdinaryFunctionCreate(intrinsics.GeneratorFunction.PrototypeObject, definition, definition.ThisMode, env, privateEnv);
closure.MakeMethod(obj);
closure.SetFunctionName(propKey);
var prototype = ObjectInstance.OrdinaryObjectCreate(engine, intrinsics.GeneratorFunction.PrototypeObject.PrototypeObject);
closure.DefinePropertyOrThrow(CommonProperties.Prototype, new PropertyDescriptor(prototype, PropertyFlag.Writable));
return DefineMethodProperty(obj, propKey, closure, enumerable);
}
else
{
var closure = intrinsics.Function.OrdinaryFunctionCreate(intrinsics.Function.PrototypeObject, definition, definition.ThisMode, env, privateEnv);
closure.MakeMethod(obj);
closure.SetFunctionName(propKey, getter ? "get" : "set");

var propDesc = new GetSetPropertyDescriptor(
getter ? closure : null,
!getter ? closure : null,
PropertyFlag.Configurable);
if (method.Key is PrivateIdentifier privateIdentifier)
{
return new PrivateElement
{
Key = privateEnv!.Names[privateIdentifier],
Kind = PrivateElementKind.Accessor,
Get = getter ? closure : null,
Set = !getter ? closure : null
};
}

obj.DefinePropertyOrThrow(propKey, propDesc);
var propDesc = new GetSetPropertyDescriptor(
getter ? closure : null,
!getter ? closure : null,
PropertyFlag.Configurable);

obj.DefinePropertyOrThrow(propKey, propDesc);
}

return null;
}
Expand All @@ -406,7 +418,7 @@ public ClassStaticBlockFunction(StaticBlock staticBlock) : base(Nodes.StaticBloc
return new PrivateElement { Key = (PrivateName) key, Kind = PrivateElementKind.Method, Value = closure };
}

var desc = new PropertyDescriptor(closure, enumerable ? PropertyFlag.Enumerable : PropertyFlag.NonEnumerable);
var desc = new PropertyDescriptor(closure, enumerable ? PropertyFlag.ConfigurableEnumerableWritable : PropertyFlag.NonEnumerable);
homeObject.DefinePropertyOrThrow(key, desc);
return null;
}
Expand Down
15 changes: 7 additions & 8 deletions Jint/Native/Function/FunctionKind.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
namespace Jint.Native.Function
namespace Jint.Native.Function;

internal enum FunctionKind
{
internal enum FunctionKind
{
Normal,
Async,
Generator,
AsyncGenerator
}
Normal,
Async,
Generator,
AsyncGenerator
}
46 changes: 46 additions & 0 deletions Jint/Native/Generator/GeneratorFunctionConstructor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Jint.Native.Function;
using Jint.Native.Iterator;
using Jint.Native.Object;
using Jint.Runtime;
using Jint.Runtime.Descriptors;

namespace Jint.Native.Generator;

/// <summary>
/// https://tc39.es/ecma262/#sec-generatorfunction-constructor
/// </summary>
internal sealed class GeneratorFunctionConstructor : Constructor
{
private static readonly JsString _functionName = new("GeneratorFunction");

internal GeneratorFunctionConstructor(
Engine engine,
Realm realm,
FunctionPrototype prototype,
IteratorPrototype iteratorPrototype)
: base(engine, realm, _functionName)
{
PrototypeObject = new GeneratorFunctionPrototype(engine, this, prototype, iteratorPrototype);
_prototype = PrototypeObject;
_prototypeDescriptor = new PropertyDescriptor(PrototypeObject, PropertyFlag.AllForbidden);
_length = new PropertyDescriptor(JsNumber.PositiveOne, PropertyFlag.Configurable);
}

public GeneratorFunctionPrototype PrototypeObject { get; }

protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
{
return Construct(arguments, thisObject);
}

public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
{
var function = _realm.Intrinsics.Function.CreateDynamicFunction(
this,
newTarget,
FunctionKind.Generator,
arguments);

return function;
}
}

0 comments on commit 3ab67e4

Please sign in to comment.