Skip to content

Commit

Permalink
Flatten declarative record instance creation lookups (#2040)
Browse files Browse the repository at this point in the history
  • Loading branch information
lahma authored Jan 25, 2025
1 parent df1cbf3 commit 815fa32
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 55 deletions.
56 changes: 35 additions & 21 deletions Jint/Collections/HybridDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,40 +119,39 @@ public void SetOrUpdateValue<TState>(Key key, Func<TValue, TState, TValue> updat
currentValue = updater(currentValue, state);
}

private bool SwitchToDictionary(Key key, TValue value, bool tryAdd)
private bool SwitchToDictionary(Key key, TValue value, bool tryAdd, int capacity = InitialDictionarySize)
{
var dictionary = new StringDictionarySlim<TValue>(InitialDictionarySize);
foreach (var pair in _list)
{
dictionary[pair.Key] = pair.Value;
}
SwitchToDictionary(capacity);

bool result;
if (tryAdd)
{
result = dictionary.TryAdd(key, value);
}
else
{
dictionary[key] = value;
result = true;
return _dictionary.TryAdd(key, value);
}

_dictionary = dictionary;
_list = null;
return result;
_dictionary[key] = value;
return true;
}

private ref TValue SwitchToDictionary(Key key, int capacity = InitialDictionarySize)
{
SwitchToDictionary(capacity);
return ref _dictionary[key];
}

private ref TValue SwitchToDictionary(Key key)
private void SwitchToDictionary(int capacity = InitialDictionarySize)
{
var dictionary = new StringDictionarySlim<TValue>(InitialDictionarySize);
foreach (var pair in _list)
var dictionary = new StringDictionarySlim<TValue>(capacity);

if (_list is not null)
{
dictionary[pair.Key] = pair.Value;
foreach (var pair in _list)
{
dictionary[pair.Key] = pair.Value;
}
}

_dictionary = dictionary;
_list = null;
return ref dictionary[key];
}

public int Count
Expand All @@ -161,6 +160,21 @@ public int Count
get => _dictionary?.Count ?? _list?.Count ?? 0;
}

public void EnsureCapacity(int capacity)
{
if (_dictionary is not null)
{
// not implemented yet
return;
}

if (capacity >= CutoverPoint)
{
SwitchToDictionary(capacity);
}
}


public bool TryAdd(Key key, TValue value)
{
if (_dictionary != null)
Expand Down
28 changes: 14 additions & 14 deletions Jint/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Jint.Collections;
using Jint.Native;
using Jint.Native.Function;
using Jint.Native.Generator;
Expand Down Expand Up @@ -1096,7 +1097,7 @@ private void GlobalDeclarationInstantiation(
// Else,
// Perform ? IteratorBindingInitialization for formals with iteratorRecord and env as arguments.

Environment varEnv;
DeclarativeEnvironment varEnv;
if (!hasParameterExpressions)
{
// NOTE: Only a single lexical environment is needed for the parameters and top-level vars.
Expand Down Expand Up @@ -1130,7 +1131,7 @@ private void GlobalDeclarationInstantiation(
// NOTE: Annex B.3.3.1 adds additional steps at this point.
// A https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation

Environment lexEnv;
DeclarativeEnvironment lexEnv;
if (!strict)
{
lexEnv = JintEnvironment.NewDeclarativeEnvironment(this, varEnv);
Expand All @@ -1146,21 +1147,20 @@ private void GlobalDeclarationInstantiation(

UpdateLexicalEnvironment(lexEnv);

if (configuration.LexicalDeclarations.Length > 0)
if (configuration.LexicalDeclarations.Count > 0)
{
foreach (var d in configuration.LexicalDeclarations)
var dictionary = lexEnv._dictionary ??= new HybridDictionary<Binding>(configuration.LexicalDeclarations.Count, checkExistingKeys: true);
dictionary.EnsureCapacity(dictionary.Count + configuration.LexicalDeclarations.Count);
for (var i = 0; i < configuration.LexicalDeclarations.Count; i++)
{
for (var j = 0; j < d.BoundNames.Count; j++)
var d = configuration.LexicalDeclarations[i];
if (d.IsConstantDeclaration)
{
var dn = d.BoundNames[j];
if (d.IsConstantDeclaration)
{
lexEnv.CreateImmutableBinding(dn, strict: true);
}
else
{
lexEnv.CreateMutableBinding(dn, canBeDeleted: false);
}
dictionary[d.BoundName] = new Binding(null!, canBeDeleted: false, mutable: false, strict);
}
else
{
dictionary[d.BoundName] = new Binding(null!, canBeDeleted: false, mutable: true, strict: false);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions Jint/Native/Function/Function.cs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ internal void OrdinaryCallBindThis(in ExecutionContext calleeContext, JsValue th
/// <summary>
/// https://tc39.es/ecma262/#sec-prepareforordinarycall
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal ref readonly ExecutionContext PrepareForOrdinaryCall(JsValue newTarget)
{
var callerContext = _engine.ExecutionContext;
Expand Down
33 changes: 13 additions & 20 deletions Jint/Runtime/Interpreter/JintFunctionDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,21 +196,14 @@ internal sealed class State
public List<Key>? VarNames;
public LinkedList<FunctionDeclaration>? FunctionsToInitialize;
public readonly HashSet<Key> FunctionNames = new();
public LexicalVariableDeclaration[] LexicalDeclarations = Array.Empty<LexicalVariableDeclaration>();
public List<LexicalVariableDeclaration> LexicalDeclarations = [];
public HashSet<Key>? ParameterBindings;
public List<VariableValuePair>? VarsToInitialize;

internal struct VariableValuePair
{
public Key Name;
public JsValue? InitialValue;
}
internal readonly record struct VariableValuePair(Key Name, JsValue? InitialValue);

internal struct LexicalVariableDeclaration
{
public bool IsConstantDeclaration;
public List<Key> BoundNames;
}
[StructLayout(LayoutKind.Auto)]
internal readonly record struct LexicalVariableDeclaration(Key BoundName, bool IsConstantDeclaration);
}

internal static State BuildState(IFunction function)
Expand Down Expand Up @@ -332,19 +325,19 @@ internal static State BuildState(IFunction function)

if (hoistingScope._lexicalDeclarations != null)
{
var _lexicalDeclarations = hoistingScope._lexicalDeclarations;
var lexicalDeclarationsCount = _lexicalDeclarations.Count;
var declarations = new State.LexicalVariableDeclaration[lexicalDeclarationsCount];
var boundNames = new List<Key>();
var lexicalDeclarations = hoistingScope._lexicalDeclarations;
var lexicalDeclarationsCount = lexicalDeclarations.Count;
var declarations = new List<State.LexicalVariableDeclaration>(lexicalDeclarationsCount);
for (var i = 0; i < lexicalDeclarationsCount; i++)
{
var d = _lexicalDeclarations[i];
var boundNames = new List<Key>();
var d = lexicalDeclarations[i];
boundNames.Clear();
d.GetBoundNames(boundNames);
declarations[i] = new State.LexicalVariableDeclaration
for (var j = 0; j < boundNames.Count; j++)
{
IsConstantDeclaration = d.IsConstantDeclaration(),
BoundNames = boundNames
};
declarations.Add(new State.LexicalVariableDeclaration(boundNames[j], d.IsConstantDeclaration()));
}
}
state.LexicalDeclarations = declarations;
}
Expand Down

0 comments on commit 815fa32

Please sign in to comment.