Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update test262 to latest and fix issues #1151

Merged
merged 7 commits into from
Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions Jint.Tests.Test262/Test262Harness.settings.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
{
"SuiteGitSha": "91356f52f92691abe62c06d00677332212e99dc8",
"SuiteGitSha": "28b31c0bf1960878abb36ab8597a0cae224a684d",
//"SuiteDirectory": "//mnt/c/work/test262",
"TargetPath": "./Generated",
"Namespace": "Jint.Tests.Test262",
"Parallel": true,
"ExcludedFeatures": [
"__getter__",
"__setter__",
"__proto__",
"AggregateError",
"async-functions",
"async-iteration",
Expand Down
23 changes: 13 additions & 10 deletions Jint/Native/Array/ArrayConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,29 +213,32 @@ private JsValue Of(JsValue thisObj, JsValue[] arguments)
if (thisObj.IsConstructor)
{
a = ((IConstructor) thisObj).Construct(new JsValue[] { len }, thisObj);
}
else
{
a = _realm.Intrinsics.Array.Construct(len);
}

if (a is ArrayInstance ai)
{
// faster for real arrays
for (uint k = 0; k < arguments.Length; k++)
{
var kValue = arguments[k];
var key = JsString.Create(k);
a.CreateDataPropertyOrThrow(key, kValue);
ai.SetIndexValue(k, kValue, updateLength: k == arguments.Length - 1);
}

a.Set(CommonProperties.Length, len, true);
}
else
{
// faster for real arrays
ArrayInstance ai;
a = ai = _realm.Intrinsics.Array.Construct(len);

// slower version
for (uint k = 0; k < arguments.Length; k++)
{
var kValue = arguments[k];
ai.SetIndexValue(k, kValue, updateLength: false);
var key = JsString.Create(k);
a.CreateDataPropertyOrThrow(key, kValue);
}

ai.SetLength((uint) arguments.Length);
a.Set(CommonProperties.Length, len, true);
}

return a;
Expand Down
156 changes: 128 additions & 28 deletions Jint/Native/Array/ArrayInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public class ArrayInstance : ObjectInstance, IEnumerable<JsValue>
internal PropertyDescriptor[] _dense;
private Dictionary<uint, PropertyDescriptor> _sparse;

private ObjectChangeFlags _objectChangeFlags;

public ArrayInstance(Engine engine, uint capacity = 0) : base(engine, ObjectClass.Array)
{
if (capacity > engine.Options.Constraints.MaxArraySize)
Expand Down Expand Up @@ -62,15 +64,59 @@ public ArrayInstance(Engine engine, Dictionary<uint, PropertyDescriptor> items)
_length = new PropertyDescriptor(length, PropertyFlag.OnlyWritable);
}

public override bool IsArrayLike => true;
public sealed override bool IsArrayLike => true;

public override bool IsArray() => true;
public sealed override bool IsArray() => true;

internal override bool HasOriginalIterator
internal sealed override bool HasOriginalIterator
=> ReferenceEquals(Get(GlobalSymbolRegistry.Iterator), _engine.Realm.Intrinsics.Array.PrototypeObject._originalIteratorFunction);

public override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc)
/// <summary>
/// Checks whether there have been changes to object prototype chain which could render fast access patterns impossible.
/// </summary>
internal bool CanUseFastAccess
{
get
{
if ((_objectChangeFlags & ObjectChangeFlags.NonDefaultDataDescriptorUsage) != 0)
{
// could be a mutating property for example, length might change, not safe anymore
return false;
}

if (_prototype is not ArrayPrototype arrayPrototype
|| !ReferenceEquals(_prototype, _engine.Realm.Intrinsics.Array.PrototypeObject))
{
// somebody has switched prototype
return false;
}

if ((arrayPrototype._objectChangeFlags & ObjectChangeFlags.ArrayIndex) != 0)
{
// maybe somebody moved integer property to prototype? not safe anymore
return false;
}

if (arrayPrototype.Prototype is not ObjectPrototype arrayPrototypePrototype
|| !ReferenceEquals(arrayPrototypePrototype, _engine.Realm.Intrinsics.Array.PrototypeObject.Prototype))
{
return false;
}

return (arrayPrototypePrototype._objectChangeFlags & ObjectChangeFlags.ArrayIndex) == 0;
}
}

public sealed override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc)
{
var isArrayIndex = IsArrayIndex(property, out var index);
TrackChanges(property, desc, isArrayIndex);

if (isArrayIndex)
{
return DefineOwnProperty(index, desc);
}

if (property == CommonProperties.Length)
{
var value = desc.Value;
Expand Down Expand Up @@ -205,11 +251,6 @@ public override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc
return true;
}

if (IsArrayIndex(property, out var index))
{
return DefineOwnProperty(index, desc);
}

return base.DefineOwnProperty(property, desc);
}

Expand Down Expand Up @@ -249,7 +290,7 @@ internal uint GetLength()
return (uint) ((JsNumber) _length._value)._value;
}

protected override void AddProperty(JsValue property, PropertyDescriptor descriptor)
protected sealed override void AddProperty(JsValue property, PropertyDescriptor descriptor)
{
if (property == CommonProperties.Length)
{
Expand All @@ -260,7 +301,7 @@ protected override void AddProperty(JsValue property, PropertyDescriptor descrip
base.AddProperty(property, descriptor);
}

protected override bool TryGetProperty(JsValue property, out PropertyDescriptor descriptor)
protected sealed override bool TryGetProperty(JsValue property, out PropertyDescriptor descriptor)
{
if (property == CommonProperties.Length)
{
Expand All @@ -271,7 +312,7 @@ protected override bool TryGetProperty(JsValue property, out PropertyDescriptor
return base.TryGetProperty(property, out descriptor);
}

public override List<JsValue> GetOwnPropertyKeys(Types types = Types.None | Types.String | Types.Symbol)
public sealed override List<JsValue> GetOwnPropertyKeys(Types types = Types.None | Types.String | Types.Symbol)
{
if ((types & Types.String) == 0)
{
Expand Down Expand Up @@ -308,7 +349,7 @@ public override List<JsValue> GetOwnPropertyKeys(Types types = Types.None | Type
return properties;
}

public override IEnumerable<KeyValuePair<JsValue, PropertyDescriptor>> GetOwnProperties()
public sealed override IEnumerable<KeyValuePair<JsValue, PropertyDescriptor>> GetOwnProperties()
{
if (_dense != null)
{
Expand Down Expand Up @@ -340,7 +381,7 @@ public override List<JsValue> GetOwnPropertyKeys(Types types = Types.None | Type
}
}

public override PropertyDescriptor GetOwnProperty(JsValue property)
public sealed override PropertyDescriptor GetOwnProperty(JsValue property)
{
if (property == CommonProperties.Length)
{
Expand Down Expand Up @@ -390,9 +431,37 @@ private PropertyDescriptor GetProperty(uint index)
return Prototype?.GetProperty(JsString.Create(index)) ?? PropertyDescriptor.Undefined;
}

protected internal override void SetOwnProperty(JsValue property, PropertyDescriptor desc)
public sealed override bool Set(JsValue property, JsValue value, JsValue receiver)
{
if (IsArrayIndex(property, out var index))
if (ReferenceEquals(receiver, this) && Extensible && IsArrayIndex(property, out var index))
{
if (TryGetDescriptor(index, out var descriptor))
{
if (descriptor.IsDefaultArrayValueDescriptor())
{
// fast path with direct write without allocations
descriptor.Value = value;
return true;
}
}
else if (CanUseFastAccess)
{
// we know it's to be written to own array backing field as new value
WriteArrayValue(index, new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable));
EnsureCorrectLength(index);
return true;
}
}

// slow path
return base.Set(property, value, receiver);
}

protected internal sealed override void SetOwnProperty(JsValue property, PropertyDescriptor desc)
{
var isArrayIndex = IsArrayIndex(property, out var index);
TrackChanges(property, desc, isArrayIndex);
if (isArrayIndex)
{
WriteArrayValue(index, desc);
}
Expand All @@ -406,7 +475,25 @@ protected internal override void SetOwnProperty(JsValue property, PropertyDescri
}
}

public override bool HasOwnProperty(JsValue p)
private void TrackChanges(JsValue property, PropertyDescriptor desc, bool isArrayIndex)
{
EnsureInitialized();
if (!desc.IsDefaultArrayValueDescriptor())
{
_objectChangeFlags |= ObjectChangeFlags.NonDefaultDataDescriptorUsage;
}

if (isArrayIndex)
{
_objectChangeFlags |= ObjectChangeFlags.ArrayIndex;
}
else
{
_objectChangeFlags |= property.IsSymbol() ? ObjectChangeFlags.Symbol : ObjectChangeFlags.Property;
}
}

public sealed override bool HasOwnProperty(JsValue p)
{
if (IsArrayIndex(p, out var index))
{
Expand All @@ -423,7 +510,7 @@ public override bool HasOwnProperty(JsValue p)
return base.HasOwnProperty(p);
}

public override void RemoveOwnProperty(JsValue p)
public sealed override void RemoveOwnProperty(JsValue p)
{
if (IsArrayIndex(p, out var index))
{
Expand All @@ -439,7 +526,7 @@ public override void RemoveOwnProperty(JsValue p)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsArrayIndex(JsValue p, out uint index)
internal static bool IsArrayIndex(JsValue p, out uint index)
{
if (p is JsNumber number)
{
Expand Down Expand Up @@ -516,15 +603,21 @@ internal void SetIndexValue(uint index, JsValue value, bool updateLength)
{
if (updateLength)
{
var length = GetLength();
if (index >= length)
{
SetLength(index + 1);
}
EnsureCorrectLength(index);
}
WriteArrayValue(index, new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnsureCorrectLength(uint index)
{
var length = GetLength();
if (index >= length)
{
SetLength(index + 1);
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void SetLength(uint length)
{
Expand Down Expand Up @@ -814,7 +907,7 @@ internal ArrayInstance Map(JsValue[] arguments)
}

/// <inheritdoc />
internal override bool FindWithCallback(
internal sealed override bool FindWithCallback(
JsValue[] arguments,
out uint index,
out JsValue value,
Expand Down Expand Up @@ -881,9 +974,9 @@ internal ArrayInstance Map(JsValue[] arguments)
return false;
}

public override uint Length => GetLength();
public sealed override uint Length => GetLength();

internal override bool IsIntegerIndexedArray => true;
internal sealed override bool IsIntegerIndexedArray => true;

public JsValue this[uint index]
{
Expand Down Expand Up @@ -943,7 +1036,7 @@ internal void CopyValues(ArrayInstance source, uint sourceStartIndex, uint targe
}
}

public override string ToString()
public sealed override string ToString()
{
// debugger can make things hard when evaluates computed values
return "(" + (_length?._value.AsNumber() ?? 0) + ")[]";
Expand All @@ -956,4 +1049,11 @@ private static void ThrowMaximumArraySizeReachedException(Engine engine, uint ca
);
}
}

internal static class ArrayPropertyDescriptorExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static bool IsDefaultArrayValueDescriptor(this PropertyDescriptor propertyDescriptor)
=> propertyDescriptor.Flags == PropertyFlag.ConfigurableEnumerableWritable && propertyDescriptor.IsDataDescriptor();
}
}
6 changes: 3 additions & 3 deletions Jint/Native/Array/ArrayOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal abstract class ArrayOperations : IEnumerable<JsValue>

public static ArrayOperations For(ObjectInstance instance)
{
if (instance is ArrayInstance arrayInstance)
if (instance is ArrayInstance { CanUseFastAccess: true } arrayInstance)
{
return new ArrayInstanceOperations(arrayInstance);
}
Expand Down Expand Up @@ -294,10 +294,10 @@ public override JsValue[] GetAll(Types elementTypes)
public override void DeletePropertyOrThrow(ulong index)
=> _target.DeletePropertyOrThrow((uint) index);

public override void CreateDataPropertyOrThrow(ulong index, JsValue value)
public override void CreateDataPropertyOrThrow(ulong index, JsValue value)
=> _target.SetIndexValue((uint) index, value, updateLength: false);

public override void Set(ulong index, JsValue value, bool updateLength = false, bool throwOnError = true)
public override void Set(ulong index, JsValue value, bool updateLength = false, bool throwOnError = true)
=> _target.SetIndexValue((uint) index, value, updateLength);
}

Expand Down