diff --git a/Jint.Benchmark/EngineConstructionBenchmark.cs b/Jint.Benchmark/EngineConstructionBenchmark.cs index 56522b1307..dc1d79fd6b 100644 --- a/Jint.Benchmark/EngineConstructionBenchmark.cs +++ b/Jint.Benchmark/EngineConstructionBenchmark.cs @@ -1,24 +1,36 @@ using BenchmarkDotNet.Attributes; using Esprima; using Esprima.Ast; +using Jint.Native; namespace Jint.Benchmark; [MemoryDiagnoser] public class EngineConstructionBenchmark { - private readonly Script _program; + private Script _program; + private Script _simple; - public EngineConstructionBenchmark() + [GlobalSetup] + public void GlobalSetup() { var parser = new JavaScriptParser(); - _program = parser.ParseScript("return [].length + ''.length"); + _program = parser.ParseScript("([].length + ''.length)"); + _simple = parser.ParseScript("1"); + new Engine().Evaluate(_program); } [Benchmark] - public double BuildEngine() + public Engine BuildEngine() { var engine = new Engine(); - return engine.Evaluate(_program).AsNumber(); + return engine; + } + + [Benchmark] + public JsValue EvaluateSimple() + { + var engine = new Engine(); + return engine.Evaluate(_simple); } } diff --git a/Jint/Collections/HybridDictionary.cs b/Jint/Collections/HybridDictionary.cs index 618e6883b8..4b27fae70b 100644 --- a/Jint/Collections/HybridDictionary.cs +++ b/Jint/Collections/HybridDictionary.cs @@ -28,6 +28,12 @@ public HybridDictionary(int initialSize, bool checkExistingKeys) } } + protected HybridDictionary(StringDictionarySlim dictionary) + { + _checkExistingKeys = true; + _dictionary = dictionary; + } + public TValue this[Key key] { get diff --git a/Jint/Collections/PropertyDictionary.cs b/Jint/Collections/PropertyDictionary.cs index daea0f27fa..41a8c54397 100644 --- a/Jint/Collections/PropertyDictionary.cs +++ b/Jint/Collections/PropertyDictionary.cs @@ -11,5 +11,9 @@ public PropertyDictionary() public PropertyDictionary(int capacity, bool checkExistingKeys) : base(capacity, checkExistingKeys) { } + + public PropertyDictionary(StringDictionarySlim properties) : base(properties) + { + } } } diff --git a/Jint/Collections/StringDictionarySlim.cs b/Jint/Collections/StringDictionarySlim.cs index fab269533a..29b534e7d3 100644 --- a/Jint/Collections/StringDictionarySlim.cs +++ b/Jint/Collections/StringDictionarySlim.cs @@ -171,6 +171,15 @@ public ref TValue GetOrAddValueRef(Key key) return ref AddKey(key, bucketIndex); } + /// + /// Adds a new item and expects key to not to exist. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddDangerous(in Key key, TValue value) + { + AddKey(key, key.HashCode & (_buckets.Length - 1)) = value; + } + public ref TValue this[Key key] { [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Jint/Engine.cs b/Jint/Engine.cs index 7fa5e8317d..b974a902b0 100644 --- a/Jint/Engine.cs +++ b/Jint/Engine.cs @@ -26,16 +26,18 @@ namespace Jint /// public sealed partial class Engine : IDisposable { + private static readonly Options _defaultEngineOptions = new(); + private readonly ParserOptions _defaultParserOptions; private readonly JavaScriptParser _defaultParser; - internal readonly ExecutionContextStack _executionContexts; + private readonly ExecutionContextStack _executionContexts; private JsValue _completionValue = JsValue.Undefined; internal EvaluationContext? _activeEvaluationContext; private readonly EventLoop _eventLoop = new(); - private readonly Agent _agent = new Agent(); + private readonly Agent _agent = new(); // lazy properties private DebugHandler? _debugHandler; @@ -51,7 +53,7 @@ public sealed partial class Engine : IDisposable internal readonly JsValueArrayPool _jsValueArrayPool; internal readonly ExtensionMethodCache _extensionMethods; - public ITypeConverter ClrTypeConverter { get; internal set; } = null!; + public ITypeConverter ClrTypeConverter { get; internal set; } // cache of types used when resolving CLR type names internal readonly Dictionary TypeCache = new(); @@ -73,7 +75,7 @@ public sealed partial class Engine : IDisposable /// /// Constructs a new engine instance. /// - public Engine() : this((Action?) null) + public Engine() : this(null, null) { } @@ -81,14 +83,14 @@ public Engine() : this((Action?) null) /// Constructs a new engine instance and allows customizing options. /// public Engine(Action? options) - : this((engine, opts) => options?.Invoke(opts)) + : this(null, options != null ? (_, opts) => options.Invoke(opts) : null) { } /// /// Constructs a new engine with a custom instance. /// - public Engine(Options options) : this((e, o) => e.Options = options) + public Engine(Options options) : this(options, null) { } @@ -96,14 +98,21 @@ public Engine(Options options) : this((e, o) => e.Options = options) /// Constructs a new engine instance and allows customizing options. /// /// The provided engine instance in callback is not guaranteed to be fully configured - public Engine(Action options) + public Engine(Action options) : this(null, options) + { + } + + private Engine(Options? options, Action? configure) { Advanced = new AdvancedOperations(this); + ClrTypeConverter = new DefaultTypeConverter(this); _executionContexts = new ExecutionContextStack(2); - Options = new Options(); - options?.Invoke(this, Options); + // we can use default options if there's no action to modify it + Options = options ?? (configure is not null ? new Options() : _defaultEngineOptions); + + configure?.Invoke(this, Options); _extensionMethods = ExtensionMethodCache.Build(Options.Interop.ExtensionMethodTypes); diff --git a/Jint/Native/Global/GlobalObject.Properties.cs b/Jint/Native/Global/GlobalObject.Properties.cs new file mode 100644 index 0000000000..a8ae037981 --- /dev/null +++ b/Jint/Native/Global/GlobalObject.Properties.cs @@ -0,0 +1,188 @@ +using Jint.Collections; +using Jint.Runtime.Descriptors; +using Jint.Runtime.Descriptors.Specialized; +using Jint.Runtime.Interop; + +namespace Jint.Native.Global; + +public partial class GlobalObject +{ + private static readonly Key propertyAggregateError = "AggregateError"; + private static readonly Key propertyArray = "Array"; + private static readonly Key propertyArrayBuffer = "ArrayBuffer"; + private static readonly Key propertyAtomics = "Atomics"; + private static readonly Key propertyBigInt = "BigInt"; + private static readonly Key propertyBigInt64Array = "BigInt64Array"; + private static readonly Key propertyBigUint64Array = "BigUint64Array"; + private static readonly Key propertyBoolean = "Boolean"; + private static readonly Key propertyDataView = "DataView"; + private static readonly Key propertyDate = "Date"; + private static readonly Key propertyError = "Error"; + private static readonly Key propertyEvalError = "EvalError"; + private static readonly Key propertyFinalizationRegistry = "FinalizationRegistry"; + private static readonly Key propertyFloat32Array = "Float32Array"; + private static readonly Key propertyFloat64Array = "Float64Array"; + private static readonly Key propertyFunction = "Function"; + private static readonly Key propertyInt16Array = "Int16Array"; + private static readonly Key propertyInt32Array = "Int32Array"; + private static readonly Key propertyInt8Array = "Int8Array"; + //private static readonly Key propertyIntl = "Intl"; + private static readonly Key propertyJSON = "JSON"; + private static readonly Key propertyMap = "Map"; + private static readonly Key propertyMath = "Math"; + private static readonly Key propertyNumber = "Number"; + private static readonly Key propertyObject = "Object"; + private static readonly Key propertyPromise = "Promise"; + private static readonly Key propertyProxy = "Proxy"; + private static readonly Key propertyRangeError = "RangeError"; + private static readonly Key propertyReferenceError = "ReferenceError"; + private static readonly Key propertyReflect = "Reflect"; + private static readonly Key propertyRegExp = "RegExp"; + private static readonly Key propertySet = "Set"; + private static readonly Key propertyShadowRealm = "ShadowRealm"; + private static readonly Key propertySharedArrayBuffer = "SharedArrayBuffer"; + private static readonly Key propertyString = "String"; + private static readonly Key propertySymbol = "Symbol"; + private static readonly Key propertySyntaxError = "SyntaxError"; + private static readonly Key propertyTypeError = "TypeError"; + private static readonly Key propertyTypedArray = "TypedArray"; + private static readonly Key propertyURIError = "URIError"; + private static readonly Key propertyUint16Array = "Uint16Array"; + private static readonly Key propertyUint32Array = "Uint32Array"; + private static readonly Key propertyUint8Array = "Uint8Array"; + private static readonly Key propertyUint8ClampedArray = "Uint8ClampedArray"; + private static readonly Key propertyWeakMap = "WeakMap"; + private static readonly Key propertyWeakRef = "WeakRef"; + private static readonly Key propertyWeakSet = "WeakSet"; + private static readonly Key propertyNaN = "NaN"; + private static readonly Key propertyInfinity = "Infinity"; + private static readonly Key propertyUndefined = "undefined"; + private static readonly Key propertyParseInt = "parseInt"; + private static readonly Key propertyParseFloat = "parseFloat"; + private static readonly Key propertyIsNaN = "isNaN"; + private static readonly Key propertyIsFinite = "isFinite"; + private static readonly Key propertyDecodeURI = "decodeURI"; + private static readonly Key propertyDecodeURIComponent = "decodeURIComponent"; + private static readonly Key propertyEncodeURI = "encodeURI"; + private static readonly Key propertyEncodeURIComponent = "encodeURIComponent"; + private static readonly Key propertyEscape = "escape"; + private static readonly Key propertyUnescape = "unescape"; + private static readonly Key propertyGlobalThis = "globalThis"; + private static readonly Key propertyEval = "eval"; + private static readonly Key propertyToString = "toString"; + + private static readonly PropertyDescriptor _propertyDescriptorNan = new(JsNumber.DoubleNaN, PropertyFlag.AllForbidden); + private static readonly PropertyDescriptor _propertyDescriptorPositiveInfinity = new(JsNumber.DoublePositiveInfinity, PropertyFlag.AllForbidden); + private static readonly PropertyDescriptor _propertyDescriptorUndefined = new(Undefined, PropertyFlag.AllForbidden); + + protected override void Initialize() + { + const PropertyFlag LengthFlags = PropertyFlag.Configurable; + const PropertyFlag PropertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable; + + var properties = new StringDictionarySlim(64); + properties.AddDangerous(propertyAggregateError, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.AggregateError, PropertyFlags)); + properties.AddDangerous(propertyArray, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Array, PropertyFlags)); + properties.AddDangerous(propertyArrayBuffer, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.ArrayBuffer, PropertyFlags)); + properties.AddDangerous(propertyAtomics, new LazyPropertyDescriptor(this, static state => Undefined, PropertyFlags)); + properties.AddDangerous(propertyBigInt, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.BigInt, PropertyFlags)); + properties.AddDangerous(propertyBigInt64Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.BigInt64Array, PropertyFlags)); + properties.AddDangerous(propertyBigUint64Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.BigUint64Array, PropertyFlags)); + properties.AddDangerous(propertyBoolean, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Boolean, PropertyFlags)); + properties.AddDangerous(propertyDataView, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.DataView, PropertyFlags)); + properties.AddDangerous(propertyDate, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Date, PropertyFlags)); + properties.AddDangerous(propertyError, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Error, PropertyFlags)); + properties.AddDangerous(propertyEvalError, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.EvalError, PropertyFlags)); + properties.AddDangerous(propertyFinalizationRegistry, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.FinalizationRegistry, PropertyFlags)); + properties.AddDangerous(propertyFloat32Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Float32Array, PropertyFlags)); + properties.AddDangerous(propertyFloat64Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Float64Array, PropertyFlags)); + properties.AddDangerous(propertyFunction, new PropertyDescriptor(_realm.Intrinsics.Function, PropertyFlags)); + properties.AddDangerous(propertyInt16Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int16Array, PropertyFlags)); + properties.AddDangerous(propertyInt32Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int32Array, PropertyFlags)); + properties.AddDangerous(propertyInt8Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int8Array, PropertyFlags)); + // TODO properties.AddDapropertygerous(propertyIntl, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Intl, propertyFlags)); + properties.AddDangerous(propertyJSON, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Json, PropertyFlags)); + properties.AddDangerous(propertyMap, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Map, PropertyFlags)); + properties.AddDangerous(propertyMath, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Math, PropertyFlags)); + properties.AddDangerous(propertyNumber, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Number, PropertyFlags)); + properties.AddDangerous(propertyObject, new PropertyDescriptor(_realm.Intrinsics.Object, PropertyFlags)); + properties.AddDangerous(propertyPromise, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Promise, PropertyFlags)); + properties.AddDangerous(propertyProxy, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Proxy, PropertyFlags)); + properties.AddDangerous(propertyRangeError, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.RangeError, PropertyFlags)); + properties.AddDangerous(propertyReferenceError, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.ReferenceError, PropertyFlags)); + properties.AddDangerous(propertyReflect, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Reflect, PropertyFlags)); + properties.AddDangerous(propertyRegExp, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.RegExp, PropertyFlags)); + properties.AddDangerous(propertySet, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Set, PropertyFlags)); + properties.AddDangerous(propertyShadowRealm, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.ShadowRealm, PropertyFlags)); + properties.AddDangerous(propertySharedArrayBuffer, new LazyPropertyDescriptor(this, static state => Undefined, PropertyFlags)); + properties.AddDangerous(propertyString, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.String, PropertyFlags)); + properties.AddDangerous(propertySymbol, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Symbol, PropertyFlags)); + properties.AddDangerous(propertySyntaxError, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.SyntaxError, PropertyFlags)); + properties.AddDangerous(propertyTypeError, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.TypeError, PropertyFlags)); + properties.AddDangerous(propertyTypedArray, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.TypedArray, PropertyFlags)); + properties.AddDangerous(propertyURIError, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.UriError, PropertyFlags)); + properties.AddDangerous(propertyUint16Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Uint16Array, PropertyFlags)); + properties.AddDangerous(propertyUint32Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Uint32Array, PropertyFlags)); + properties.AddDangerous(propertyUint8Array, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Uint8Array, PropertyFlags)); + properties.AddDangerous(propertyUint8ClampedArray, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Uint8ClampedArray, PropertyFlags)); + properties.AddDangerous(propertyWeakMap, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.WeakMap, PropertyFlags)); + properties.AddDangerous(propertyWeakRef, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.WeakRef, PropertyFlags)); + properties.AddDangerous(propertyWeakSet, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.WeakSet, PropertyFlags)); + + properties.AddDangerous(propertyNaN, _propertyDescriptorNan); + properties.AddDangerous(propertyInfinity, _propertyDescriptorPositiveInfinity); + properties.AddDangerous(propertyUndefined, _propertyDescriptorUndefined); + properties.AddDangerous(propertyParseInt, new LazyPropertyDescriptor(this, static state => new ClrFunctionInstance(((GlobalObject) state!)._engine, "parseInt", ParseInt, 2, LengthFlags), PropertyFlags)); + properties.AddDangerous(propertyParseFloat, new LazyPropertyDescriptor(this, static state => new ClrFunctionInstance(((GlobalObject) state!)._engine, "parseFloat", ParseFloat, 1, LengthFlags), PropertyFlags)); + properties.AddDangerous(propertyIsNaN, new LazyPropertyDescriptor(this, static state => new ClrFunctionInstance(((GlobalObject) state!)._engine, "isNaN", IsNaN, 1, LengthFlags), PropertyFlags)); + properties.AddDangerous(propertyIsFinite, new LazyPropertyDescriptor(this, static state => new ClrFunctionInstance(((GlobalObject) state!)._engine, "isFinite", IsFinite, 1, LengthFlags), PropertyFlags)); + + properties.AddDangerous(propertyDecodeURI, new LazyPropertyDescriptor(this, static state => + { + var global = (GlobalObject) state!; + return new ClrFunctionInstance(global._engine, "decodeURI", global.DecodeUri, 1, LengthFlags); + }, PropertyFlags)); + + properties.AddDangerous(propertyDecodeURIComponent, new LazyPropertyDescriptor(this, static state => + { + var global = (GlobalObject) state!; + return new ClrFunctionInstance(global._engine, "decodeURIComponent", global.DecodeUriComponent, 1, LengthFlags); + }, PropertyFlags)); + + properties.AddDangerous(propertyEncodeURI, new LazyPropertyDescriptor(this, static state => + { + var global = (GlobalObject) state!; + return new ClrFunctionInstance(global._engine, "encodeURI", global.EncodeUri, 1, LengthFlags); + }, PropertyFlags)); + + properties.AddDangerous(propertyEncodeURIComponent, new LazyPropertyDescriptor(this, static state => + { + var global = (GlobalObject) state!; + return new ClrFunctionInstance(global._engine, "encodeURIComponent", global.EncodeUriComponent, 1, LengthFlags); + }, PropertyFlags)); + + properties.AddDangerous(propertyEscape, new LazyPropertyDescriptor(this, static state => + { + var global = (GlobalObject) state!; + return new ClrFunctionInstance(global._engine, "escape", global.Escape, 1, LengthFlags); + }, PropertyFlags)); + + properties.AddDangerous(propertyUnescape, new LazyPropertyDescriptor(this, static state => + { + var global = (GlobalObject) state!; + return new ClrFunctionInstance(global._engine, "unescape", global.Unescape, 1, LengthFlags); + }, PropertyFlags)); + + properties.AddDangerous(propertyGlobalThis, new PropertyDescriptor(this, PropertyFlags)); + properties.AddDangerous(propertyEval, new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Eval, PropertyFlag.Configurable | PropertyFlag.Writable)); + + // toString is not mentioned or actually required in spec, but some tests rely on it + properties.AddDangerous(propertyToString, new LazyPropertyDescriptor(this, static state => + { + var global = (GlobalObject) state!; + return new ClrFunctionInstance(global._engine, "toString", global.ToStringString, 1); + }, PropertyFlags)); + + SetProperties(properties); + } +} diff --git a/Jint/Native/Global/GlobalObject.cs b/Jint/Native/Global/GlobalObject.cs index 5390fc0e05..4496af979b 100644 --- a/Jint/Native/Global/GlobalObject.cs +++ b/Jint/Native/Global/GlobalObject.cs @@ -13,7 +13,7 @@ namespace Jint.Native.Global { - public sealed class GlobalObject : ObjectInstance + public sealed partial class GlobalObject : ObjectInstance { private readonly Realm _realm; private readonly StringBuilder _stringBuilder = new(); @@ -25,113 +25,6 @@ internal GlobalObject( _realm = realm; } - protected override void Initialize() - { - const PropertyFlag lengthFlags = PropertyFlag.Configurable; - const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable; - - var properties = new PropertyDictionary(56, checkExistingKeys: false) - { - ["AggregateError"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.AggregateError, propertyFlags), - ["Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Array, propertyFlags), - ["ArrayBuffer"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.ArrayBuffer, propertyFlags), - ["Atomics"] = new LazyPropertyDescriptor(this, static state => Undefined, propertyFlags), - ["BigInt"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.BigInt, propertyFlags), - ["BigInt64Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.BigInt64Array, propertyFlags), - ["BigUint64Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.BigUint64Array, propertyFlags), - ["Boolean"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Boolean, propertyFlags), - ["DataView"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.DataView, propertyFlags), - ["Date"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Date, propertyFlags), - ["Error"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Error, propertyFlags), - ["EvalError"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.EvalError, propertyFlags), - ["FinalizationRegistry"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.FinalizationRegistry, propertyFlags), - ["Float32Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Float32Array, propertyFlags), - ["Float64Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Float64Array, propertyFlags), - ["Function"] = new PropertyDescriptor(_realm.Intrinsics.Function, propertyFlags), - ["Int16Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int16Array, propertyFlags), - ["Int32Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int32Array, propertyFlags), - ["Int8Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Int8Array, propertyFlags), - // TODO ["Intl"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Intl, propertyFlags), - ["JSON"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Json, propertyFlags), - ["Map"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Map, propertyFlags), - ["Math"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Math, propertyFlags), - ["Number"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Number, propertyFlags), - ["Object"] = new PropertyDescriptor(_realm.Intrinsics.Object, propertyFlags), - ["Promise"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Promise, propertyFlags), - ["Proxy"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Proxy, propertyFlags), - ["RangeError"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.RangeError, propertyFlags), - ["ReferenceError"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.ReferenceError, propertyFlags), - ["Reflect"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Reflect, propertyFlags), - ["RegExp"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.RegExp, propertyFlags), - ["Set"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Set, propertyFlags), - ["ShadowRealm"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.ShadowRealm, propertyFlags), - ["SharedArrayBuffer"] = new LazyPropertyDescriptor(this, static state => Undefined, propertyFlags), - ["String"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.String, propertyFlags), - ["Symbol"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Symbol, propertyFlags), - ["SyntaxError"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.SyntaxError, propertyFlags), - ["TypeError"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.TypeError, propertyFlags), - ["TypedArray"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.TypedArray, propertyFlags), - ["URIError"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.UriError, propertyFlags), - ["Uint16Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Uint16Array, propertyFlags), - ["Uint32Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Uint32Array, propertyFlags), - ["Uint8Array"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Uint8Array, propertyFlags), - ["Uint8ClampedArray"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Uint8ClampedArray, propertyFlags), - ["WeakMap"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.WeakMap, propertyFlags), - ["WeakRef"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.WeakRef, propertyFlags), - ["WeakSet"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.WeakSet, propertyFlags), - - - ["NaN"] = new PropertyDescriptor(double.NaN, PropertyFlag.AllForbidden), - ["Infinity"] = new PropertyDescriptor(double.PositiveInfinity, PropertyFlag.AllForbidden), - ["undefined"] = new PropertyDescriptor(Undefined, PropertyFlag.AllForbidden), - ["parseInt"] = new LazyPropertyDescriptor(this, static state => new ClrFunctionInstance(((GlobalObject) state!)._engine, "parseInt", ParseInt, 2, lengthFlags), propertyFlags), - ["parseFloat"] = new LazyPropertyDescriptor(this, static state => new ClrFunctionInstance(((GlobalObject) state!)._engine, "parseFloat", ParseFloat, 1, lengthFlags), propertyFlags), - ["isNaN"] = new LazyPropertyDescriptor(this, static state => new ClrFunctionInstance(((GlobalObject) state!)._engine, "isNaN", IsNaN, 1, lengthFlags), propertyFlags), - ["isFinite"] = new LazyPropertyDescriptor(this, static state => new ClrFunctionInstance(((GlobalObject) state!)._engine, "isFinite", IsFinite, 1, lengthFlags), propertyFlags), - ["decodeURI"] = new LazyPropertyDescriptor(this, static state => - { - var global = (GlobalObject) state!; - return new ClrFunctionInstance(global._engine, "decodeURI", global.DecodeUri, 1, lengthFlags); - }, propertyFlags), - ["decodeURIComponent"] = new LazyPropertyDescriptor(this, static state => - { - var global = (GlobalObject) state!; - return new ClrFunctionInstance(global._engine, "decodeURIComponent", global.DecodeUriComponent, 1, lengthFlags); - }, propertyFlags), - ["encodeURI"] = new LazyPropertyDescriptor(this, static state => - { - var global = (GlobalObject) state!; - return new ClrFunctionInstance(global._engine, "encodeURI", global.EncodeUri, 1, lengthFlags); - }, propertyFlags), - ["encodeURIComponent"] = new LazyPropertyDescriptor(this, static state => - { - var global = (GlobalObject) state!; - return new ClrFunctionInstance(global._engine, "encodeURIComponent", global.EncodeUriComponent, 1, lengthFlags); - }, propertyFlags), - ["escape"] = new LazyPropertyDescriptor(this, static state => - { - var global = (GlobalObject) state!; - return new ClrFunctionInstance(global._engine, "escape", global.Escape, 1, lengthFlags); - }, propertyFlags), - ["unescape"] = new LazyPropertyDescriptor(this, static state => - { - var global = (GlobalObject) state!; - return new ClrFunctionInstance(global._engine, "unescape", global.Unescape, 1, lengthFlags); - }, propertyFlags), - ["globalThis"] = new PropertyDescriptor(this, propertyFlags), - ["eval"] = new LazyPropertyDescriptor(this, static state => ((GlobalObject) state!)._realm.Intrinsics.Eval, PropertyFlag.Configurable | PropertyFlag.Writable), - - // toString is not mentioned or actually required in spec, but some tests rely on it - ["toString"] = new LazyPropertyDescriptor(this, static state => - { - var global = (GlobalObject) state!; - return new ClrFunctionInstance(global._engine, "toString", global.ToStringString, 1); - }, propertyFlags) - }; - - SetProperties(properties); - } - private JsValue ToStringString(JsValue thisObject, JsValue[] arguments) { return _realm.Intrinsics.Object.PrototypeObject.ToObjectString(thisObject, Arguments.Empty); diff --git a/Jint/Native/Object/ObjectInstance.cs b/Jint/Native/Object/ObjectInstance.cs index 4bdb5fba63..ec09c45cca 100644 --- a/Jint/Native/Object/ObjectInstance.cs +++ b/Jint/Native/Object/ObjectInstance.cs @@ -130,6 +130,8 @@ internal static IConstructor SpeciesConstructor(ObjectInstance o, IConstructor d return null; } + internal void SetProperties(StringDictionarySlim properties) => SetProperties(new PropertyDictionary(properties)); + internal void SetProperties(PropertyDictionary? properties) { if (properties != null) diff --git a/Jint/Options.cs b/Jint/Options.cs index 4224613a3a..56f7b4d236 100644 --- a/Jint/Options.cs +++ b/Jint/Options.cs @@ -21,8 +21,10 @@ namespace Jint public class Options { - private ITimeSystem? _timeSystem; + private static readonly CultureInfo _defaultCulture = CultureInfo.CurrentCulture; + private static readonly TimeZoneInfo _defaultTimeZone = TimeZoneInfo.Local; + private ITimeSystem? _timeSystem; internal List> _configurations { get; } = new(); /// @@ -58,7 +60,7 @@ public class Options /// /// The culture the engine runs on, defaults to current culture. /// - public CultureInfo Culture { get; set; } = CultureInfo.CurrentCulture; + public CultureInfo Culture { get; set; } = _defaultCulture; /// @@ -73,7 +75,7 @@ public ITimeSystem TimeSystem /// /// The time zone the engine runs on, defaults to local. Same as setting DefaultTimeSystem with the time zone. /// - public TimeZoneInfo TimeZone { get; set; } = TimeZoneInfo.Local; + public TimeZoneInfo TimeZone { get; set; } = _defaultTimeZone; /// /// Reference resolver allows customizing behavior for reference resolving. This can be useful in cases where @@ -106,7 +108,7 @@ internal void Apply(Engine engine) { foreach (var configuration in _configurations) { - configuration?.Invoke(engine); + configuration(engine); } // add missing bits if needed @@ -145,9 +147,6 @@ internal void Apply(Engine engine) } engine.ModuleLoader = Modules.ModuleLoader; - - // ensure defaults - engine.ClrTypeConverter ??= new DefaultTypeConverter(engine); } private static void AttachExtensionMethodsToPrototypes(Engine engine) diff --git a/Jint/Runtime/Descriptors/PropertyDescriptor.cs b/Jint/Runtime/Descriptors/PropertyDescriptor.cs index 9f32fa7030..f9dcf6fe71 100644 --- a/Jint/Runtime/Descriptors/PropertyDescriptor.cs +++ b/Jint/Runtime/Descriptors/PropertyDescriptor.cs @@ -18,11 +18,13 @@ public PropertyDescriptor() : this(PropertyFlag.None) { } + [MethodImpl(MethodImplOptions.AggressiveInlining)] protected PropertyDescriptor(PropertyFlag flags) { _flags = flags; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] protected internal PropertyDescriptor(JsValue? value, PropertyFlag flags) : this(flags) { if ((_flags & PropertyFlag.CustomJsValue) != 0) @@ -32,6 +34,7 @@ protected internal PropertyDescriptor(JsValue? value, PropertyFlag flags) : this _value = value; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public PropertyDescriptor(JsValue? value, bool? writable, bool? enumerable, bool? configurable) { if ((_flags & PropertyFlag.CustomJsValue) != 0) diff --git a/Jint/Runtime/Descriptors/Specialized/LazyPropertyDescriptor.cs b/Jint/Runtime/Descriptors/Specialized/LazyPropertyDescriptor.cs index 7c2eaec1df..2d13df852f 100644 --- a/Jint/Runtime/Descriptors/Specialized/LazyPropertyDescriptor.cs +++ b/Jint/Runtime/Descriptors/Specialized/LazyPropertyDescriptor.cs @@ -1,3 +1,4 @@ +using System.Runtime.CompilerServices; using Jint.Native; namespace Jint.Runtime.Descriptors.Specialized @@ -7,6 +8,7 @@ internal sealed class LazyPropertyDescriptor : PropertyDescriptor private readonly object? _state; private readonly Func _resolver; + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal LazyPropertyDescriptor(object? state, Func resolver, PropertyFlag flags) : base(null, flags | PropertyFlag.CustomJsValue) {