Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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