Skip to content

Commit

Permalink
tweaks and fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Dec 13, 2021
1 parent d596697 commit 0b8ad1d
Show file tree
Hide file tree
Showing 16 changed files with 253 additions and 53 deletions.
12 changes: 10 additions & 2 deletions Jint.Tests/Runtime/TypedArrayInteropTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public void CanInteropWithBigInt64()
var engine = new Engine();
var source = new BigInteger[] { 42, 12 };
engine.SetValue("testSubject", engine.Realm.Intrinsics.BigInt64Array.Construct(source));
ValidateCreatedTypeArray(engine, "BigInt64Array");
ValidateCreatedBigIntegerTypeArray(engine, "BigInt64Array");

var fromEngine = engine.GetValue("testSubject");
Assert.True(fromEngine.IsBigInt64Array());
Expand All @@ -116,7 +116,7 @@ public void CanInteropWithBigUint64()
var engine = new Engine();
var source = new BigInteger[] { 42, 12 };
engine.SetValue("testSubject", engine.Realm.Intrinsics.BigUint64Array.Construct(source));
ValidateCreatedTypeArray(engine, "BigUint64Array");
ValidateCreatedBigIntegerTypeArray(engine, "BigUint64Array");

var fromEngine = engine.GetValue("testSubject");
Assert.True(fromEngine.IsBigUint64Array());
Expand All @@ -130,5 +130,13 @@ private static void ValidateCreatedTypeArray(Engine engine, string arrayName)
Assert.Equal(42, engine.Evaluate("testSubject[0]").AsNumber());
Assert.Equal(12, engine.Evaluate("testSubject[1]").AsNumber());
}

private static void ValidateCreatedBigIntegerTypeArray(Engine engine, string arrayName)
{
Assert.Equal(arrayName, engine.Evaluate("testSubject.constructor.name").AsString());
Assert.Equal(2, engine.Evaluate("testSubject.length").AsNumber());
Assert.Equal(42, engine.Evaluate("testSubject[0]").AsBigInt());
Assert.Equal(12, engine.Evaluate("testSubject[1]").AsBigInt());
}
}
}
8 changes: 3 additions & 5 deletions Jint/JsValueExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,13 +357,12 @@ public static bool IsBigInt64Array(this JsValue value)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static BigInteger[] AsBigInt64Array(this JsValue value)
{
if (!value.IsUint32Array())
if (!value.IsBigInt64Array())
{
ThrowWrongTypeException(value, "BigInt64Array");
}

ExceptionHelper.ThrowNotImplementedException();
return null;
return ((TypedArrayInstance) value).ToNativeArray<BigInteger>();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -380,8 +379,7 @@ public static BigInteger[] AsBigUint64Array(this JsValue value)
ThrowWrongTypeException(value, "BigUint64Array");
}

ExceptionHelper.ThrowNotImplementedException();
return null;
return ((TypedArrayInstance) value).ToNativeArray<BigInteger>();
}

[Pure]
Expand Down
3 changes: 1 addition & 2 deletions Jint/Native/ArrayBuffer/ArrayBufferInstance.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Numerics;
using Jint.Native.Object;
using Jint.Native.TypedArray;
using Jint.Runtime;
Expand Down Expand Up @@ -151,7 +150,7 @@ internal TypedArrayValue RawBytesToNumeric(TypedArrayElementType type, int byteI
{
// return the BigInt value that corresponds to intValue
#if NETSTANDARD2_1
return new BigInteger(rawBytes.AsSpan().Slice(byteIndex, 16));
return new System.Numerics.BigInteger(rawBytes.AsSpan().Slice(byteIndex, 8));
#else
ExceptionHelper.ThrowNotImplementedException();
#endif
Expand Down
26 changes: 19 additions & 7 deletions Jint/Native/BigInt/BigIntConstructor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Jint.Collections;
using System;
using System.Numerics;
using Jint.Collections;
using Jint.Native.Function;
using Jint.Native.Object;
using Jint.Runtime;
Expand Down Expand Up @@ -31,8 +33,8 @@ protected override void Initialize()
{
var properties = new PropertyDictionary(2, checkExistingKeys: false)
{
["asIntN"] = new(new ClrFunctionInstance(Engine, "asIntN", AsIntN, 1, PropertyFlag.Configurable), true, false, true),
["asUintN"] = new(new ClrFunctionInstance(Engine, "asUintN", AsUintN, 1, PropertyFlag.Configurable), true, false, true),
["asIntN"] = new(new ClrFunctionInstance(Engine, "asIntN", AsIntN, 2, PropertyFlag.Configurable), true, false, true),
["asUintN"] = new(new ClrFunctionInstance(Engine, "asUintN", AsUintN, 2, PropertyFlag.Configurable), true, false, true),
};
SetProperties(properties);
}
Expand All @@ -43,11 +45,21 @@ protected override void Initialize()
private JsValue AsIntN(JsValue thisObj, JsValue[] arguments)
{
var bits = TypeConverter.ToIndex(_realm, arguments.At(0));

if (bits == 0)
{
return JsBigInt.Zero;
}

var bigint = TypeConverter.ToBigInt(arguments.At(1));
// Let mod be ℝ(bigint) modulo 2bits.
// 4. If mod ≥ 2bits - 1, return ℤ(mod - 2bits); otherwise, return ℤ(mod).
return JsBigInt.Create(bits * bigint);
var bitsPow = (int) System.Math.Pow(2, bits);
var mod = bigint % bitsPow;
if (mod >= bitsPow - 1)
{
return mod - bitsPow;
}

return mod;
}

/// <summary>
Expand All @@ -58,7 +70,7 @@ private JsValue AsUintN(JsValue thisObj, JsValue[] arguments)
var bits = TypeConverter.ToIndex(_realm, arguments.At(0));
var bigint = TypeConverter.ToBigInt(arguments.At(1));

return JsBigInt.Create(bits * bigint);
return JsBigInt.Create(bigint % (BigInteger) System.Math.Pow(2, bits));
}

public override JsValue Call(JsValue thisObject, JsValue[] arguments)
Expand Down
6 changes: 2 additions & 4 deletions Jint/Native/DataView/DataViewPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,10 @@ private JsValue SetUint32(JsValue thisObj, JsValue[] arguments)

var getIndex = TypeConverter.ToIndex(_realm, requestIndex);

double numberValue;
TypedArrayValue numberValue;
if (type.IsBigIntElementType())
{
// let numberValue be ? ToBigInt(value).
ExceptionHelper.ThrowNotImplementedException("BigInt not implemented");
return Undefined;
numberValue = TypeConverter.ToBigInt(value);
}
else
{
Expand Down
8 changes: 4 additions & 4 deletions Jint/Native/Json/JsonSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ public JsValue Serialize(JsValue value, JsValue replacer, JsValue space)
private JsValue Str(JsValue key, JsValue holder)
{
var value = holder.Get(key, holder);
if (value.IsObject())
if (value.IsObject() || value.IsBigInt())
{
var toJson = value.AsObject().Get("toJSON", value);
var toJson = value.Get("toJSON", value);
if (toJson.IsObject())
{
if (toJson.AsObject() is ICallable callableToJson)
Expand Down Expand Up @@ -189,9 +189,9 @@ private JsValue Str(JsValue key, JsValue holder)
return JsString.NullString;
}

if (value is JsBigInt bigInt)
if (value.Type == Types.BigInt)
{
return "\"" + bigInt._value.ToString("R") + "\"";
ExceptionHelper.ThrowTypeError(_engine.Realm, "Do not know how to serialize a BigInt");
}

var isCallable = value.IsObject() && value.AsObject() is ICallable;
Expand Down
35 changes: 24 additions & 11 deletions Jint/Native/Number/NumberConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,35 +114,48 @@ private static JsValue IsSafeInteger(JsValue thisObj, JsValue[] arguments)

public override JsValue Call(JsValue thisObject, JsValue[] arguments)
{
if (arguments.Length == 0)
{
return 0d;
}

return TypeConverter.ToNumber(arguments[0]);
var n = ProcessFirstParameter(arguments);
return n;
}

/// <summary>
/// https://tc39.es/ecma262/#sec-number-constructor-number-value
/// </summary>
public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
{
var value = arguments.Length > 0
? JsNumber.Create(TypeConverter.ToNumber(arguments[0]))
: JsNumber.PositiveZero;
var n = ProcessFirstParameter(arguments);

if (newTarget.IsUndefined())
{
return Construct(value);
return Construct(n);
}

var o = OrdinaryCreateFromConstructor(
newTarget,
static intrinsics => intrinsics.Number.PrototypeObject,
static (engine, realm, state) => new NumberInstance(engine, (JsNumber) state), value);
static (engine, realm, state) => new NumberInstance(engine, (JsNumber) state), n);
return o;
}

private static JsNumber ProcessFirstParameter(JsValue[] arguments)
{
var n = JsNumber.PositiveZero;
if (arguments.Length > 0)
{
var prim = TypeConverter.ToNumeric(arguments[0]);
if (prim.IsBigInt())
{
n = JsNumber.Create((long) ((JsBigInt) prim)._value);
}
else
{
n = (JsNumber) prim;
}
}

return n;
}

public NumberPrototype PrototypeObject { get; private set; }

public NumberInstance Construct(JsNumber value)
Expand Down
2 changes: 1 addition & 1 deletion Jint/Native/Number/NumberInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public NumberInstance(Engine engine, JsNumber value)

JsValue IPrimitiveInstance.PrimitiveValue => NumberData;

public JsNumber NumberData { get; set; }
public JsNumber NumberData { get; internal init; }

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsNegativeZero(double x)
Expand Down
7 changes: 7 additions & 0 deletions Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1350,6 +1350,13 @@ public int Compare(JsValue x, JsValue y)
return (int) v;
}

if (x.Type == Types.BigInt || y.Type == Types.BigInt)
{
var xBigInt = TypeConverter.ToBigInt(x);
var yBigInt = TypeConverter.ToBigInt(y);
return xBigInt.CompareTo(yBigInt);
}

var xValue = x.AsNumber();
var yValue = y.AsNumber();

Expand Down
4 changes: 2 additions & 2 deletions Jint/Native/TypedArray/TypedArrayElementType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ internal static byte GetElementSize(this TypedArrayElementType type)
TypedArrayElementType.Uint16 => 2,
TypedArrayElementType.Int32 => 4,
TypedArrayElementType.Uint32 => 4,
TypedArrayElementType.BigInt64 => 16,
TypedArrayElementType.BigUint64 => 16,
TypedArrayElementType.BigInt64 => 8,
TypedArrayElementType.BigUint64 => 8,
TypedArrayElementType.Float32 => 4,
TypedArrayElementType.Float64 => 8,
_ => 0
Expand Down
99 changes: 98 additions & 1 deletion Jint/Native/TypedArray/TypedArrayValue.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Numerics;
using Jint.Runtime;

Expand All @@ -6,7 +7,7 @@ namespace Jint.Native.TypedArray;
/// <summary>
/// Container for either double or BigInteger.
/// </summary>
internal readonly record struct TypedArrayValue(Types Type, double DoubleValue, BigInteger BigInteger)
internal readonly record struct TypedArrayValue(Types Type, double DoubleValue, BigInteger BigInteger) : IConvertible
{
public static implicit operator TypedArrayValue(double value)
{
Expand All @@ -24,4 +25,100 @@ public JsValue ToJsValue()
? JsNumber.Create(DoubleValue)
: JsBigInt.Create(BigInteger);
}

public TypeCode GetTypeCode()
{
ExceptionHelper.ThrowNotImplementedException();
return default;
}

public bool ToBoolean(IFormatProvider provider)
{
ExceptionHelper.ThrowNotImplementedException();
return default;
}

public char ToChar(IFormatProvider provider)
{
ExceptionHelper.ThrowNotImplementedException();
return default;
}

public sbyte ToSByte(IFormatProvider provider)
{
return (sbyte) DoubleValue;
}

public byte ToByte(IFormatProvider provider)
{
return (byte) DoubleValue;
}

public short ToInt16(IFormatProvider provider)
{
return (short) DoubleValue;
}

public ushort ToUInt16(IFormatProvider provider)
{
return (ushort) DoubleValue;
}

public int ToInt32(IFormatProvider provider)
{
return (int) DoubleValue;
}

public uint ToUInt32(IFormatProvider provider)
{
return (uint) DoubleValue;
}

public long ToInt64(IFormatProvider provider)
{
return (long) DoubleValue;
}

public ulong ToUInt64(IFormatProvider provider)
{
return (ulong) DoubleValue;
}

public float ToSingle(IFormatProvider provider)
{
return (float) DoubleValue;
}

public double ToDouble(IFormatProvider provider)
{
return DoubleValue;
}

public decimal ToDecimal(IFormatProvider provider)
{
return (decimal) DoubleValue;
}

public DateTime ToDateTime(IFormatProvider provider)
{
ExceptionHelper.ThrowNotImplementedException();
return default;
}

public string ToString(IFormatProvider provider)
{
ExceptionHelper.ThrowNotImplementedException();
return default;
}

public object ToType(Type conversionType, IFormatProvider provider)
{
if (conversionType == typeof(BigInteger) && Type == Types.BigInt)
{
return BigInteger;
}

ExceptionHelper.ThrowNotImplementedException();
return default;
}
}

0 comments on commit 0b8ad1d

Please sign in to comment.