Skip to content

Commit

Permalink
Improve global object setup and access performance (#1280)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma committed Sep 3, 2022
1 parent 3eddf04 commit 3a3e57c
Show file tree
Hide file tree
Showing 29 changed files with 338 additions and 200 deletions.
38 changes: 21 additions & 17 deletions Jint/Collections/HybridDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,22 @@ public bool TryGetValue(Key key, out TValue value)
return false;
}

public void SetOrUpdateValue<TState>(Key key, Func<TValue, TState, TValue> updater, TState state)
{
if (_dictionary != null)
{
_dictionary.SetOrUpdateValue(key, updater, state);
}
else if (_list != null)
{
_list.SetOrUpdateValue(key, updater, state);
}
else
{
_list = new ListDictionary<TValue>(key, updater(default, state), _checkExistingKeys);
}
}

private void SwitchToDictionary(Key key, TValue value)
{
var dictionary = new StringDictionarySlim<TValue>(InitialDictionarySize);
Expand Down Expand Up @@ -122,19 +138,8 @@ public void Add(Key key, TValue value)

public void Clear()
{
if (_dictionary != null)
{
var dictionary = _dictionary;
_dictionary = null;
dictionary.Clear();
}

if (_list != null)
{
var cachedList = _list;
_list = null;
cachedList.Clear();
}
_dictionary?.Clear();
_list?.Clear();
}

public bool ContainsKey(Key key)
Expand All @@ -144,10 +149,9 @@ public bool ContainsKey(Key key)
return _dictionary.ContainsKey(key);
}

var cachedList = _list;
if (cachedList != null)
if (_list != null)
{
return cachedList.ContainsKey(key);
return _list.ContainsKey(key);
}

return false;
Expand Down Expand Up @@ -193,7 +197,7 @@ public bool Remove(Key key)

return _list != null && _list.Remove(key);
}

/// <summary>
/// Optimization when no need to check for existing items.
/// </summary>
Expand Down
20 changes: 19 additions & 1 deletion Jint/Collections/ListDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public ListDictionary(Key key, TValue value, bool checkExistingKeys)
_checkExistingKeys = checkExistingKeys;
_head = new DictionaryNode
{
Key = key,
Key = key,
Value = value
};
_count = 1;
Expand Down Expand Up @@ -75,6 +75,24 @@ public bool TryGetValue(Key key, out TValue value)
return false;
}

public void SetOrUpdateValue<TState>(Key key, Func<TValue, TState, TValue> updater, TState state)
{
DictionaryNode last = null;
DictionaryNode node;
for (node = _head; node != null; node = node.Next)
{
if (node.Key == key)
{
node.Value = updater(node.Value, state);
return;
}

last = node;
}

AddNode(key, updater(default, state), last);
}

public int Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
12 changes: 9 additions & 3 deletions Jint/Collections/StringDictionarySlim.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,13 @@ public bool Remove(Key key)
return false;
}

// Not safe for concurrent _reads_ (at least, if either of them add)
public void SetOrUpdateValue<TState>(Key key, Func<TValue, TState, TValue> updater, TState state)
{
ref var currentValue = ref GetOrAddValueRef(key);
currentValue = updater(currentValue, state);
}

// Not safe for concurrent _reads_ (at least, if either of them add)
// For concurrent reads, prefer TryGetValue(key, out value)
/// <summary>
/// Gets the value for the specified key, or, if the key is not present,
Expand Down Expand Up @@ -222,7 +228,7 @@ private Entry[] Resize()

return entries;
}

/// <summary>
/// Gets an enumerator over the dictionary
/// </summary>
Expand Down Expand Up @@ -286,7 +292,7 @@ void IEnumerator.Reset()

public void Dispose() { }
}

internal static class HashHelpers
{
internal static readonly int[] SizeOneIntArray = new int[1];
Expand Down
6 changes: 2 additions & 4 deletions Jint/Native/Global/GlobalObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ public sealed class GlobalObject : ObjectInstance
Realm realm) : base(engine)
{
_realm = realm;
// this is implementation dependent, and only to pass some unit tests
_prototype = realm.Intrinsics.Object.PrototypeObject;
}

protected override void Initialize()
Expand Down Expand Up @@ -798,14 +796,14 @@ internal PropertyDescriptor GetOwnProperty(Key property)
return descriptor ?? PropertyDescriptor.Undefined;
}

internal bool Set(Key property, JsValue value)
internal bool SetFromMutableBinding(Key property, JsValue value)
{
// here we are called only from global environment record context
// we can take some shortcuts to be faster

if (!_properties!.TryGetValue(property, out var existingDescriptor))
{
_properties[property] = new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable);
_properties[property] = new PropertyDescriptor(value, PropertyFlag.ConfigurableEnumerableWritable | PropertyFlag.MutableBinding);
return true;
}

Expand Down
13 changes: 5 additions & 8 deletions Jint/Native/Object/ObjectInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -643,21 +643,18 @@ public bool DefinePropertyOrThrow(JsValue property, PropertyDescriptor desc)
}

/// <summary>
/// Creates or alters the named own property to
/// have the state described by a Property
/// Descriptor. The flag controls failure handling.
/// Creates or alters the named own property to have the state described by a PropertyDescriptor.
/// </summary>
public virtual bool DefineOwnProperty(JsValue property, PropertyDescriptor desc)
{
var current = GetOwnProperty(property);
var extensible = Extensible;

if (current == desc)
{
return true;
}

return ValidateAndApplyPropertyDescriptor(this, property, extensible, desc, current);
return ValidateAndApplyPropertyDescriptor(this, property, Extensible, desc, current);
}

/// <summary>
Expand All @@ -673,7 +670,7 @@ protected static bool ValidateAndApplyPropertyDescriptor(ObjectInstance? o, JsVa
return false;
}

if (o is object)
if (o is not null)
{
if (desc.IsGenericDescriptor() || desc.IsDataDescriptor())
{
Expand Down Expand Up @@ -762,7 +759,7 @@ protected static bool ValidateAndApplyPropertyDescriptor(ObjectInstance? o, JsVa
return false;
}

if (o is object)
if (o is not null)
{
var flags = current.Flags & ~(PropertyFlag.Writable | PropertyFlag.WritableSet | PropertyFlag.CustomJsValue);
if (current.IsDataDescriptor())
Expand Down Expand Up @@ -814,7 +811,7 @@ protected static bool ValidateAndApplyPropertyDescriptor(ObjectInstance? o, JsVa
}
}

if (o is object)
if (o is not null)
{
if (!ReferenceEquals(descValue, null))
{
Expand Down
15 changes: 9 additions & 6 deletions Jint/Runtime/Completion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public enum CompletionType : byte
[StructLayout(LayoutKind.Auto)]
public readonly struct Completion
{
internal static readonly Node _emptyNode = new Identifier("");
private static readonly Node _emptyNode = new Identifier("");
private static readonly Completion _emptyCompletion = new(CompletionType.Normal, null!, _emptyNode);

internal readonly SyntaxElement _source;
Expand All @@ -36,13 +36,19 @@ internal Completion(CompletionType type, JsValue value, string? target, SyntaxEl
}

public Completion(CompletionType type, JsValue value, SyntaxElement source)
: this(type, value, null, source)
{
Type = type;
Value = value;
Target = null;
_source = source;
}

public Completion(CompletionType type, string target, SyntaxElement source)
: this(type, null!, target, source)
{
Type = type;
Value = null!;
Target = target;
_source = source;
}

internal Completion(in ExpressionResult result)
Expand All @@ -59,9 +65,6 @@ internal Completion(in ExpressionResult result)
public readonly string? Target;
public ref readonly Location Location => ref _source.Location;

public static Completion Normal(JsValue value, Node source)
=> new Completion(CompletionType.Normal, value, source);

public static ref readonly Completion Empty() => ref _emptyCompletion;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
6 changes: 3 additions & 3 deletions Jint/Runtime/Debugger/DebugScopes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ namespace Jint.Runtime.Debugger
{
public sealed class DebugScopes : IReadOnlyList<DebugScope>
{
private readonly HashSet<string> _foundBindings = new HashSet<string>();
private readonly List<DebugScope> _scopes = new List<DebugScope>();
private readonly HashSet<string> _foundBindings = new();
private readonly List<DebugScope> _scopes = new();

internal DebugScopes(EnvironmentRecord environment)
{
Expand Down Expand Up @@ -44,7 +44,7 @@ private void Populate(EnvironmentRecord? environment)
case GlobalEnvironmentRecord global:
// Similarly to Chromium, we split the Global environment into Global and Script scopes
AddScope(DebugScopeType.Script, global._declarativeRecord);
AddScope(DebugScopeType.Global, global._objectRecord);
AddScope(DebugScopeType.Global, new ObjectEnvironmentRecord(environment._engine, global._global, false, false));
break;
case FunctionEnvironmentRecord:
AddScope(inLocalScope ? DebugScopeType.Local : DebugScopeType.Closure, record);
Expand Down

0 comments on commit 3a3e57c

Please sign in to comment.