Explorar o código

Optimize engine construction (#1621)

Marko Lahma hai 1 ano
pai
achega
7fd4893131

+ 17 - 5
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);
     }
 }

+ 6 - 0
Jint/Collections/HybridDictionary.cs

@@ -28,6 +28,12 @@ namespace Jint.Collections
             }
         }
 
+        protected HybridDictionary(StringDictionarySlim<TValue> dictionary)
+        {
+            _checkExistingKeys = true;
+            _dictionary = dictionary;
+        }
+
         public TValue this[Key key]
         {
             get

+ 4 - 0
Jint/Collections/PropertyDictionary.cs

@@ -11,5 +11,9 @@ namespace Jint.Collections
         public PropertyDictionary(int capacity, bool checkExistingKeys) : base(capacity, checkExistingKeys)
         {
         }
+
+        public PropertyDictionary(StringDictionarySlim<PropertyDescriptor> properties) : base(properties)
+        {
+        }
     }
 }

+ 9 - 0
Jint/Collections/StringDictionarySlim.cs

@@ -171,6 +171,15 @@ namespace Jint.Collections
             return ref AddKey(key, bucketIndex);
         }
 
+        /// <summary>
+        /// Adds a new item and expects key to not to exist.
+        /// </summary>
+        [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)]

+ 18 - 9
Jint/Engine.cs

@@ -26,16 +26,18 @@ namespace Jint
     /// </summary>
     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 @@ namespace Jint
         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<string, Type?> TypeCache = new();
@@ -73,7 +75,7 @@ namespace Jint
         /// <summary>
         /// Constructs a new engine instance.
         /// </summary>
-        public Engine() : this((Action<Options>?) null)
+        public Engine() : this(null, null)
         {
         }
 
@@ -81,14 +83,14 @@ namespace Jint
         /// Constructs a new engine instance and allows customizing options.
         /// </summary>
         public Engine(Action<Options>? options)
-            : this((engine, opts) => options?.Invoke(opts))
+            : this(null, options != null ? (_, opts) => options.Invoke(opts) : null)
         {
         }
 
         /// <summary>
         /// Constructs a new engine with a custom <see cref="Options"/> instance.
         /// </summary>
-        public Engine(Options options) : this((e, o) => e.Options = options)
+        public Engine(Options options) : this(options, null)
         {
         }
 
@@ -96,14 +98,21 @@ namespace Jint
         /// Constructs a new engine instance and allows customizing options.
         /// </summary>
         /// <remarks>The provided engine instance in callback is not guaranteed to be fully configured</remarks>
-        public Engine(Action<Engine, Options> options)
+        public Engine(Action<Engine, Options> options) : this(null, options)
+        {
+        }
+
+        private Engine(Options? options, Action<Engine, Options>? 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);
 

+ 188 - 0
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<PropertyDescriptor>(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);
+    }
+}

+ 1 - 108
Jint/Native/Global/GlobalObject.cs

@@ -13,7 +13,7 @@ using Jint.Runtime.Interop;
 
 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 @@ namespace Jint.Native.Global
             _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);

+ 2 - 0
Jint/Native/Object/ObjectInstance.cs

@@ -130,6 +130,8 @@ namespace Jint.Native.Object
             return null;
         }
 
+        internal void SetProperties(StringDictionarySlim<PropertyDescriptor> properties) => SetProperties(new PropertyDictionary(properties));
+
         internal void SetProperties(PropertyDictionary? properties)
         {
             if (properties != null)

+ 6 - 7
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<Action<Engine>> _configurations { get; } = new();
 
         /// <summary>
@@ -58,7 +60,7 @@ namespace Jint
         /// <summary>
         /// The culture the engine runs on, defaults to current culture.
         /// </summary>
-        public CultureInfo Culture { get; set; } = CultureInfo.CurrentCulture;
+        public CultureInfo Culture { get; set; } = _defaultCulture;
 
 
         /// <summary>
@@ -73,7 +75,7 @@ namespace Jint
         /// <summary>
         /// The time zone the engine runs on, defaults to local. Same as setting DefaultTimeSystem with the time zone.
         /// </summary>
-        public TimeZoneInfo TimeZone { get; set; } = TimeZoneInfo.Local;
+        public TimeZoneInfo TimeZone { get; set; } = _defaultTimeZone;
 
         /// <summary>
         /// Reference resolver allows customizing behavior for reference resolving. This can be useful in cases where
@@ -106,7 +108,7 @@ namespace Jint
         {
             foreach (var configuration in _configurations)
             {
-                configuration?.Invoke(engine);
+                configuration(engine);
             }
 
             // add missing bits if needed
@@ -145,9 +147,6 @@ namespace Jint
             }
 
             engine.ModuleLoader = Modules.ModuleLoader;
-
-            // ensure defaults
-            engine.ClrTypeConverter ??= new DefaultTypeConverter(engine);
         }
 
         private static void AttachExtensionMethodsToPrototypes(Engine engine)

+ 3 - 0
Jint/Runtime/Descriptors/PropertyDescriptor.cs

@@ -18,11 +18,13 @@ namespace Jint.Runtime.Descriptors
         {
         }
 
+        [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 @@ namespace Jint.Runtime.Descriptors
             _value = value;
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public PropertyDescriptor(JsValue? value, bool? writable, bool? enumerable, bool? configurable)
         {
             if ((_flags & PropertyFlag.CustomJsValue) != 0)

+ 2 - 0
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 @@ namespace Jint.Runtime.Descriptors.Specialized
         private readonly object? _state;
         private readonly Func<object?, JsValue> _resolver;
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal LazyPropertyDescriptor(object? state, Func<object?, JsValue> resolver, PropertyFlag flags)
             : base(null, flags | PropertyFlag.CustomJsValue)
         {