Skip to content

Commit

Permalink
Fix issues related to JSON, Math, RegExp and Proxy (#1045)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma authored Jan 9, 2022
1 parent f2e4404 commit 8f0d433
Show file tree
Hide file tree
Showing 9 changed files with 227 additions and 125 deletions.
2 changes: 1 addition & 1 deletion Jint/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ Engine DoInvoke()
return this;
}

var strict = _isStrict | script.Strict;
var strict = _isStrict || script.Strict;
ExecuteWithConstraints(strict, DoInvoke);

return this;
Expand Down
7 changes: 4 additions & 3 deletions Jint/Native/Array/ArrayConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -348,12 +348,13 @@ private ArrayInstance Construct(JsValue[] arguments, uint capacity, ObjectInstan
/// <summary>
/// https://tc39.es/ecma262/#sec-arraycreate
/// </summary>
private ArrayInstance ArrayCreate(uint capacity, ObjectInstance proto)
internal ArrayInstance ArrayCreate(uint length, ObjectInstance proto = null)
{
proto ??= PrototypeObject;
var instance = new ArrayInstance(Engine, capacity)
var instance = new ArrayInstance(Engine, length)
{
_prototype = proto
_prototype = proto,
_length = new PropertyDescriptor(length, PropertyFlag.OnlyWritable)
};
return instance;
}
Expand Down
2 changes: 1 addition & 1 deletion Jint/Native/BigInt/BigIntPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal BigIntPrototype(
Realm realm,
BigIntConstructor constructor,
ObjectPrototype objectPrototype)
: base(engine)
: base(engine, ObjectClass.Object, InternalTypes.BigInt)
{
_prototype = objectPrototype;
_realm = realm;
Expand Down
13 changes: 6 additions & 7 deletions Jint/Native/JsValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,8 @@ public virtual bool IsLooselyEqual(JsValue value)
return true;
}

// TODO move to type specific IsLooselyEqual

var x = this;
var y = value;

Expand All @@ -311,14 +313,12 @@ public virtual bool IsLooselyEqual(JsValue value)
return x.IsLooselyEqual(TypeConverter.ToNumber(y));
}

const InternalTypes stringOrNumber = InternalTypes.String | InternalTypes.Integer | InternalTypes.Number | InternalTypes.BigInt;

if (y.IsObject() && (x._type & stringOrNumber) != 0)
if (y.IsObject() && (x._type & InternalTypes.Primitive) != 0)
{
return x.IsLooselyEqual(TypeConverter.ToPrimitive(y));
}

if (x.IsObject() && (y._type & stringOrNumber) != 0)
if (x.IsObject() && (y._type & InternalTypes.Primitive) != 0)
{
return y.IsLooselyEqual(TypeConverter.ToPrimitive(x));
}
Expand Down Expand Up @@ -500,13 +500,12 @@ internal static bool SameValue(JsValue x, JsValue y)

internal static IConstructor AssertConstructor(Engine engine, JsValue c)
{
var constructor = c as IConstructor;
if (constructor is null)
if (!c.IsConstructor)
{
ExceptionHelper.ThrowTypeError(engine.Realm, c + " is not a constructor");
}

return constructor;
return (IConstructor) c;
}
}
}
72 changes: 36 additions & 36 deletions Jint/Native/Json/JsonSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using Jint.Collections;
using Jint.Native.BigInt;
using Jint.Native.Boolean;
Expand Down Expand Up @@ -40,43 +39,47 @@ public JsValue Serialize(JsValue value, JsValue replacer, JsValue space)
return Undefined.Instance;
}

if (replacer.IsObject())
if (replacer is ObjectInstance oi)
{
if (replacer is ICallable)
if (oi.IsCallable)
{
_replacerFunction = replacer;
}
else
{
var replacerObj = replacer.AsObject();
_propertyList = new List<JsValue>();

foreach (var pair in replacerObj.GetOwnProperties())
if (oi.IsArray())
{
var v = replacerObj.UnwrapJsValue(pair.Value);
string item = null;
if (v.IsString())
{
item = v.ToString();
}
else if (v.IsNumber())
{
item = TypeConverter.ToString(v);
}
else if (v.IsObject())
_propertyList = new List<JsValue>();
var len = oi.Length;
var k = 0;
while (k < len)
{
var propertyObj = v.AsObject();
if (propertyObj.Class == ObjectClass.String || propertyObj.Class == ObjectClass.Number)
var prop = JsString.Create(k);
var v = replacer.Get(prop);
var item = JsValue.Undefined;
if (v.IsString())
{
item = v;
}
else if (v.IsNumber())
{
item = TypeConverter.ToString(v);
}
}
else if (v.IsObject())
{
if (v is StringInstance or NumberInstance)
{
item = TypeConverter.ToString(v);
}
}

if (item != null && !_propertyList.Contains(item))
{
_propertyList.Add(item);
}
if (!item.IsUndefined() && !_propertyList.Contains(item))
{
_propertyList.Add(item);
}

k++;
}
}
}
}
Expand Down Expand Up @@ -141,27 +144,26 @@ private JsValue SerializeJSONProperty(JsValue key, JsValue holder)
{
if (toJson.AsObject() is ICallable callableToJson)
{
value = callableToJson.Call(value, Arguments.From(key));
value = callableToJson.Call(value, Arguments.From(TypeConverter.ToPropertyKey(key)));
}
}
}

if (!_replacerFunction.IsUndefined())
{
var replacerFunctionCallable = (ICallable) _replacerFunction.AsObject();
value = replacerFunctionCallable.Call(holder, Arguments.From(key, value));
value = replacerFunctionCallable.Call(holder, Arguments.From(TypeConverter.ToPropertyKey(key), value));
}

if (value.IsObject())
{
var valueObj = value.AsObject();
switch (valueObj)
switch (value)
{
case NumberInstance numberInstance:
value = numberInstance.NumberData;
case NumberInstance:
value = TypeConverter.ToNumber(value);
break;
case StringInstance stringInstance:
value = stringInstance.StringData;
case StringInstance:
value = TypeConverter.ToString(value);
break;
case BooleanInstance booleanInstance:
value = booleanInstance.BooleanData;
Expand Down Expand Up @@ -326,9 +328,7 @@ private string SerializeJSONObject(ObjectInstance value)
var stepback = _indent;
_indent += _gap;

var k = _propertyList ?? value.GetOwnProperties()
.Where(x => !x.Key.IsSymbol() && x.Value.Enumerable)
.Select(x => x.Key);
var k = (IEnumerable<JsValue>) _propertyList ?? value.EnumerableOwnPropertyNames(ObjectInstance.EnumerableOwnPropertyNamesKind.Key);

var partial = new List<string>();
foreach (var p in k)
Expand Down
108 changes: 74 additions & 34 deletions Jint/Native/Math/MathInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ private static JsValue Ceil(JsValue thisObject, JsValue[] arguments)
return JsNumber.NegativeZero;
}
#endif

return System.Math.Ceiling(x);
}

Expand Down Expand Up @@ -600,66 +600,68 @@ private static JsValue Log10(JsValue thisObject, JsValue[] arguments)
return System.Math.Log10(x);
}

/// <summary>
/// https://tc39.es/ecma262/#sec-math.max
/// </summary>
private static JsValue Max(JsValue thisObject, JsValue[] arguments)
{
if (arguments.Length == 0)
{
return JsNumber.DoubleNegativeInfinity;
}

double max = TypeConverter.ToNumber(arguments.At(0));

if (double.IsNaN(max))
{
return JsNumber.DoubleNaN;
}

for (int i = 0; i < arguments.Length; i++)
var highest = double.NegativeInfinity;
foreach (var number in Coerced(arguments))
{
var value = TypeConverter.ToNumber(arguments[i]);

if (double.IsNaN(value))
if (double.IsNaN(number))
{
return JsNumber.DoubleNaN;
}

if (max == 0 && value == 0)
if (NumberInstance.IsPositiveZero(number) && NumberInstance.IsNegativeZero(highest))
{
max = NumberInstance.IsNegativeZero(value)
? max
: value;
highest = 0;
}
else

if (number > highest)
{
max = System.Math.Max(max, value);
highest = number;
}
}
return max;

return highest;
}

/// <summary>
/// https://tc39.es/ecma262/#sec-math.min
/// </summary>
private static JsValue Min(JsValue thisObject, JsValue[] arguments)
{
if (arguments.Length == 0)
{
return JsNumber.DoublePositiveInfinity;
}

double min = TypeConverter.ToNumber(arguments.At(0));
for (int i = 0; i < arguments.Length; i++)
var lowest = double.PositiveInfinity;
foreach (var number in Coerced(arguments))
{
var value = TypeConverter.ToNumber(arguments[i]);
if (min == 0 && value == 0)
if (double.IsNaN(number))
{
min = NumberInstance.IsNegativeZero(min)
? min
: value;
return JsNumber.DoubleNaN;
}
else

if (NumberInstance.IsNegativeZero(number) && NumberInstance.IsPositiveZero(lowest))
{
min = System.Math.Min(min, value);
lowest = JsNumber.NegativeZero._value;
}

if (number < lowest)
{
lowest = number;
}
}
return min;

return lowest;
}

private static JsValue Pow(JsValue thisObject, JsValue[] arguments)
Expand All @@ -677,7 +679,7 @@ private static JsValue Pow(JsValue thisObject, JsValue[] arguments)
{
return 1;
}

return HandlePowUnlikely(y, x);
}

Expand Down Expand Up @@ -822,7 +824,7 @@ private JsValue Random(JsValue thisObject, JsValue[] arguments)
{
_random = new Random();
}

return _random.NextDouble();
}

Expand Down Expand Up @@ -997,21 +999,59 @@ private static JsValue Cbrt(JsValue thisObject, JsValue[] arguments)
return -1 * System.Math.Pow(System.Math.Abs(x), 1.0 / 3.0);
}

/// <summary>
/// https://tc39.es/ecma262/#sec-math.hypot
/// </summary>
private static JsValue Hypot(JsValue thisObject, JsValue[] arguments)
{
double y = 0;
for (int i = 0; i < arguments.Length; ++i)
var coerced = Coerced(arguments);

foreach (var number in coerced)
{
var number = TypeConverter.ToNumber(arguments[i]);
if (double.IsInfinity(number))
{
return JsNumber.DoublePositiveInfinity;
}
}

var onlyZero = true;
double y = 0;
foreach (var number in coerced)
{
if (double.IsNaN(number))
{
return JsNumber.DoubleNaN;
}

if (onlyZero && number != 0)
{
onlyZero = false;
}

y += number * number;
}

if (onlyZero)
{
return JsNumber.PositiveZero;
}

return System.Math.Sqrt(y);
}

private static double[] Coerced(JsValue[] arguments)
{
// TODO stackalloc
var coerced = new double[arguments.Length];
for (var i = 0; i < arguments.Length; i++)
{
var argument = arguments[i];
coerced[i] = TypeConverter.ToNumber(argument);
}

return coerced;
}

private static JsValue Imul(JsValue thisObject, JsValue[] arguments)
{
var x = TypeConverter.ToInt32(arguments.At(0));
Expand Down
Loading

0 comments on commit 8f0d433

Please sign in to comment.