Skip to content

Commit

Permalink
Implement ShadowRealm
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed May 22, 2022
1 parent 05ddb01 commit a84bce0
Show file tree
Hide file tree
Showing 28 changed files with 648 additions and 153 deletions.
4 changes: 2 additions & 2 deletions Jint.Tests.Test262/Test262Harness.settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,13 @@
"generators",
"hashbang",
"import-assertions",
"numeric-separator-literal",
"Promise.allSettled",
"Promise.any",
"regexp-match-indices",
"regexp-named-groups",
"regexp-lookbehind",
"regexp-unicode-property-escapes",
"resizable-arraybuffer",
"ShadowRealm",
"SharedArrayBuffer",
"tail-call-optimization",
"top-level-await",
Expand Down Expand Up @@ -215,6 +213,8 @@
"language/statements/async-function/*.js",
"language/expressions/async-function/*.js",
"language/expressions/async-generator/*.js",
"built-ins/ShadowRealm/prototype/evaluate/wrapped-functions-share-no-properties-extended.js",
"built-ins/ShadowRealm/prototype/evaluate/wrapped-function-from-return-values-share-no-identity.js",

// special casing data
"built-ins/**/special_casing*.js",
Expand Down
4 changes: 2 additions & 2 deletions Jint.Tests/Jint.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">$(TargetFrameworks);net461</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">$(TargetFrameworks);net462</TargetFrameworks>
<AssemblyOriginatorKeyFile>..\Jint\Jint.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<IsPackable>false</IsPackable>
Expand All @@ -15,7 +15,7 @@
<ProjectReference Include="..\Jint\Jint.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" Condition=" '$(TargetFramework)' == 'net461' " />
<Reference Include="Microsoft.CSharp" Condition=" '$(TargetFramework)' == 'net462' " />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Flurl.Http.Signed" Version="3.2.0" />
Expand Down
34 changes: 18 additions & 16 deletions Jint.Tests/Runtime/ModuleTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#if(NET6_0_OR_GREATER)
using System.IO;
using System.Reflection;
#endif
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -302,18 +300,16 @@ public void ShouldAllowCyclicImport()
Assert.Equal("a", nsA.Get("a").AsString());
Assert.Equal("b", nsB.Get("b").AsString());
}

[Fact]
public void ShouldSupportConstraints()
{
var engine = new Engine(opts => opts.TimeoutInterval(TimeSpan.FromTicks(1)));

engine.AddModule("my-module", @"for(var i = 0; i < 100000; i++) { } export const result = 'ok';");
Assert.Throws<TimeoutException>(() => engine.ImportModule("my-module"));
}

#if(NET6_0_OR_GREATER)

[Fact]
public void CanLoadModuleImportsFromFiles()
{
Expand All @@ -333,16 +329,22 @@ public void CanImportFromFile()

Assert.Equal("John Doe", result);
}
private static string GetBasePath()

internal static string GetBasePath()
{
var assemblyPath = new Uri(typeof(ModuleTests).GetTypeInfo().Assembly.Location).LocalPath;
var assemblyDirectory = new FileInfo(assemblyPath).Directory;
return Path.Combine(
assemblyDirectory?.Parent?.Parent?.Parent?.FullName ?? throw new NullReferenceException("Could not find tests base path"),
"Runtime",
"Scripts");
}
var assemblyDirectory = new DirectoryInfo(AppDomain.CurrentDomain.RelativeSearchPath ?? AppDomain.CurrentDomain.BaseDirectory);

var current = assemblyDirectory;
while (current is not null && current.Name != "Jint.Tests")
{
current = current.Parent;
}

#endif
if (current is null)
{
throw new NullReferenceException($"Could not find tests base path, assemblyPath: {assemblyDirectory}");
}

return Path.Combine(current.FullName, "Runtime", "Scripts");
}
}
32 changes: 32 additions & 0 deletions Jint.Tests/Runtime/ShadowRealmTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Jint.Native;
using Jint.Native.Object;
using Xunit;

namespace Jint.Tests.Runtime;

public class ShadowRealmTests
{
[Fact]
public void CanUseViaEngineMethods()
{
var engine = new Engine(options => options.EnableModules(ModuleTests.GetBasePath()));
var shadowRealm1 = engine.Realm.Intrinsics.ShadowRealm.Construct();

// lexically scoped (let/const) are visible during single call
Assert.Equal(123, shadowRealm1.Evaluate("const s = 123; const f = () => s; f();"));
Assert.Equal(true, shadowRealm1.Evaluate("typeof f === 'undefined'"));

// vars hold longer
Assert.Equal(456, shadowRealm1.Evaluate("function foo() { return 456; }; foo();"));
Assert.Equal(456, shadowRealm1.Evaluate("foo();"));

// not visible in global engine though
Assert.Equal(true, engine.Evaluate("typeof foo === 'undefined'"));

// modules
var importValue = shadowRealm1.ImportValue("./modules/format-name.js", "formatName");
var formatName = (ObjectInstance) importValue.UnwrapIfPromise();
var result = engine.Invoke(formatName, "John", "Doe").AsString();
Assert.Equal("John Doe", result);
}
}
2 changes: 1 addition & 1 deletion Jint/Jint.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NeutralLanguage>en-US</NeutralLanguage>
<TargetFrameworks>net461;netstandard2.0;netstandard2.1</TargetFrameworks>
<TargetFrameworks>net462;netstandard2.0;netstandard2.1</TargetFrameworks>
<AssemblyOriginatorKeyFile>Jint.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<LangVersion>latest</LangVersion>
Expand Down
23 changes: 3 additions & 20 deletions Jint/Native/Array/ArrayInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ internal bool CanUseFastAccess
// could be a mutating property for example, length might change, not safe anymore
return false;
}
if (_prototype is not ArrayPrototype arrayPrototype

if (_prototype is not ArrayPrototype arrayPrototype
|| !ReferenceEquals(_prototype, _engine.Realm.Intrinsics.Array.PrototypeObject))
{
// somebody has switched prototype
Expand All @@ -97,7 +97,7 @@ internal bool CanUseFastAccess
return false;
}

if (arrayPrototype.Prototype is not ObjectPrototype arrayPrototypePrototype
if (arrayPrototype.Prototype is not ObjectPrototype arrayPrototypePrototype
|| !ReferenceEquals(arrayPrototypePrototype, _engine.Realm.Intrinsics.Array.PrototypeObject.Prototype))
{
return false;
Expand Down Expand Up @@ -493,23 +493,6 @@ private void TrackChanges(JsValue property, PropertyDescriptor desc, bool isArra
}
}

public sealed override bool HasOwnProperty(JsValue p)
{
if (IsArrayIndex(p, out var index))
{
return index < GetLength()
&& (_sparse == null || _sparse.ContainsKey(index))
&& (_dense == null || (index < (uint) _dense.Length && _dense[index] != null));
}

if (p == CommonProperties.Length)
{
return _length != null;
}

return base.HasOwnProperty(p);
}

public sealed override void RemoveOwnProperty(JsValue p)
{
if (IsArrayIndex(p, out var index))
Expand Down
2 changes: 1 addition & 1 deletion Jint/Native/Function/EvalFunctionInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Jint.Native.Function
{
public sealed class EvalFunctionInstance : FunctionInstance
{
private static readonly ParserOptions ParserOptions = new ParserOptions { AdaptRegexp = true, Tolerant = false };
private static readonly ParserOptions ParserOptions = new ParserOptions { Tolerant = false };
private static readonly JsString _functionName = new JsString("eval");

public EvalFunctionInstance(
Expand Down
2 changes: 1 addition & 1 deletion Jint/Native/Function/FunctionConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace Jint.Native.Function
/// </summary>
public sealed class FunctionConstructor : FunctionInstance, IConstructor
{
private static readonly ParserOptions ParserOptions = new ParserOptions { AdaptRegexp = true, Tolerant = false };
private static readonly ParserOptions ParserOptions = new ParserOptions { Tolerant = false };
private static readonly JsString _functionName = new JsString("Function");
private static readonly JsString _functionNameAnonymous = new JsString("anonymous");

Expand Down
33 changes: 5 additions & 28 deletions Jint/Native/Function/FunctionInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,24 +162,6 @@ protected internal override void SetOwnProperty(JsValue property, PropertyDescri
}
}

public override bool HasOwnProperty(JsValue property)
{
if (property == CommonProperties.Prototype)
{
return _prototypeDescriptor != null;
}
if (property == CommonProperties.Length)
{
return _length != null;
}
if (property == CommonProperties.Name)
{
return _nameDescriptor != null;
}

return base.HasOwnProperty(property);
}

public override void RemoveOwnProperty(JsValue property)
{
if (property == CommonProperties.Prototype)
Expand Down Expand Up @@ -388,6 +370,11 @@ internal void MakeConstructor(bool writableProperty = true, ObjectInstance proto
_prototypeDescriptor = new PropertyDescriptor(prototype, writableProperty, enumerable: false, configurable: false);
}

internal void SetFunctionLength(JsNumber length)
{
DefinePropertyOrThrow(CommonProperties.Length, new PropertyDescriptor(length, writable: false, enumerable: false, configurable: true));
}

public override string ToString()
{
// TODO no way to extract SourceText from Esprima at the moment, just returning native code
Expand Down Expand Up @@ -444,16 +431,6 @@ protected internal override void SetOwnProperty(JsValue property, PropertyDescri
}
}

public override bool HasOwnProperty(JsValue property)
{
if (property == CommonProperties.Constructor)
{
return _constructor != null;
}

return base.HasOwnProperty(property);
}

public override void RemoveOwnProperty(JsValue property)
{
if (property == CommonProperties.Constructor)
Expand Down
13 changes: 7 additions & 6 deletions Jint/Native/Function/FunctionPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,20 @@ private static JsValue HasInstance(JsValue thisObj, JsValue[] arguments)
/// </summary>
private JsValue Bind(JsValue thisObj, JsValue[] arguments)
{
if (thisObj is not ICallable)
if (thisObj is not (ICallable and ObjectInstance oi))
{
ExceptionHelper.ThrowTypeError(_realm, "Bind must be called on a function");
return default;
}

var thisArg = arguments.At(0);
var f = BoundFunctionCreate((ObjectInstance) thisObj, thisArg, arguments.Skip(1));
var f = BoundFunctionCreate(oi, thisArg, arguments.Skip(1));

JsNumber l;
var targetHasLength = thisObj.HasOwnProperty(CommonProperties.Length);
var targetHasLength = oi.HasOwnProperty(CommonProperties.Length) == true;
if (targetHasLength)
{
var targetLen = thisObj.Get(CommonProperties.Length);
var targetLen = oi.Get(CommonProperties.Length);
if (targetLen is not JsNumber number)
{
l = JsNumber.PositiveZero;
Expand Down Expand Up @@ -102,7 +103,7 @@ private JsValue Bind(JsValue thisObj, JsValue[] arguments)

f.DefinePropertyOrThrow(CommonProperties.Length, new PropertyDescriptor(l, PropertyFlag.Configurable));

var targetName = thisObj.Get(CommonProperties.Name);
var targetName = oi.Get(CommonProperties.Name);
if (!targetName.IsString())
{
targetName = JsString.Empty;
Expand Down Expand Up @@ -207,4 +208,4 @@ protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments
return Undefined;
}
}
}
}

0 comments on commit a84bce0

Please sign in to comment.