Skip to content

Commit 675ad49

Browse files
authored
Support caching of string instances in script preparation (#1678)
1 parent 791384f commit 675ad49

File tree

18 files changed

+155
-97
lines changed

18 files changed

+155
-97
lines changed

Jint.Benchmark/EngineComparisonBenchmark.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ public void NilJS()
9393
public void YantraJS()
9494
{
9595
var engine = new YantraJS.Core.JSContext();
96-
engine.Eval(_files[FileName]);
96+
// By default YantraJS is strict mode only, in strict mode
97+
// we need to pass `this` explicitly in global context
98+
// if script is expecting global context as `this`
99+
engine.Eval(_files[FileName], null, engine);
97100
}
98101
}

Jint/Engine.Ast.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Esprima;
22
using Esprima.Ast;
3+
using Jint.Native;
34
using Jint.Runtime.Environments;
45
using Jint.Runtime.Interpreter;
56
using Jint.Runtime.Interpreter.Expressions;
@@ -54,7 +55,7 @@ public void NodeVisitor(Node node)
5455

5556
if (!_bindingNames.TryGetValue(name, out var bindingName))
5657
{
57-
_bindingNames[name] = bindingName = new EnvironmentRecord.BindingName(name);
58+
_bindingNames[name] = bindingName = new EnvironmentRecord.BindingName(JsString.CachedCreate(name));
5859
}
5960

6061
node.AssociatedData = bindingName;
@@ -63,6 +64,9 @@ public void NodeVisitor(Node node)
6364
case Nodes.Literal:
6465
node.AssociatedData = JintLiteralExpression.ConvertToJsValue((Literal) node);
6566
break;
67+
case Nodes.MemberExpression:
68+
node.AssociatedData = JintMemberExpression.InitializeDeterminedProperty((MemberExpression) node, cache: true);
69+
break;
6670
case Nodes.ArrowFunctionExpression:
6771
case Nodes.FunctionDeclaration:
6872
case Nodes.FunctionExpression:

Jint/Engine.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ internal JsValue GetValue(Reference reference, bool returnReferenceToPool)
641641

642642
private bool TryHandleStringValue(JsValue property, JsString s, ref ObjectInstance? o, out JsValue jsValue)
643643
{
644-
if (property == CommonProperties.Length)
644+
if (CommonProperties.Length.Equals(property))
645645
{
646646
jsValue = JsNumber.Create((uint) s.Length);
647647
return true;

Jint/Native/Array/ArrayInstance.cs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ internal bool CanUseFastAccess
107107

108108
public sealed override bool DefineOwnProperty(JsValue property, PropertyDescriptor desc)
109109
{
110-
if (property == CommonProperties.Length)
110+
if (CommonProperties.Length.Equals(property))
111111
{
112112
return DefineLength(desc);
113113
}
@@ -296,7 +296,7 @@ internal uint GetLength()
296296

297297
protected sealed override void AddProperty(JsValue property, PropertyDescriptor descriptor)
298298
{
299-
if (property == CommonProperties.Length)
299+
if (CommonProperties.Length.Equals(property ))
300300
{
301301
_length = descriptor;
302302
return;
@@ -307,7 +307,7 @@ protected sealed override void AddProperty(JsValue property, PropertyDescriptor
307307

308308
protected sealed override bool TryGetProperty(JsValue property, [NotNullWhen(true)] out PropertyDescriptor? descriptor)
309309
{
310-
if (property == CommonProperties.Length)
310+
if (CommonProperties.Length.Equals(property))
311311
{
312312
descriptor = _length;
313313
return _length != null;
@@ -416,7 +416,7 @@ public sealed override IEnumerable<KeyValuePair<JsValue, PropertyDescriptor>> Ge
416416

417417
public sealed override PropertyDescriptor GetOwnProperty(JsValue property)
418418
{
419-
if (property == CommonProperties.Length)
419+
if (CommonProperties.Length.Equals(property))
420420
{
421421
return _length ?? PropertyDescriptor.Undefined;
422422
}
@@ -451,7 +451,7 @@ public sealed override JsValue Get(JsValue property, JsValue receiver)
451451
return value;
452452
}
453453

454-
if (property == CommonProperties.Length)
454+
if (CommonProperties.Length.Equals(property))
455455
{
456456
var length = _length?._value;
457457
if (length is not null)
@@ -468,13 +468,13 @@ public sealed override bool Set(JsValue property, JsValue value, JsValue receive
468468
var isSafeSelfTarget = IsSafeSelfTarget(receiver);
469469
if (isSafeSelfTarget && CanUseFastAccess)
470470
{
471-
if (IsArrayIndex(property, out var index))
471+
if (!ReferenceEquals(property, CommonProperties.Length) && IsArrayIndex(property, out var index))
472472
{
473473
SetIndexValue(index, value, updateLength: true);
474474
return true;
475475
}
476476

477-
if (property == CommonProperties.Length
477+
if (CommonProperties.Length.Equals(property)
478478
&& _length is { Writable: true }
479479
&& value is JsNumber jsNumber
480480
&& jsNumber.IsInteger()
@@ -532,7 +532,7 @@ protected internal sealed override void SetOwnProperty(JsValue property, Propert
532532
{
533533
WriteArrayValue(index, desc);
534534
}
535-
else if (property == CommonProperties.Length)
535+
else if (CommonProperties.Length.Equals(property))
536536
{
537537
_length = desc;
538538
}
@@ -564,33 +564,33 @@ private void TrackChanges(JsValue property, PropertyDescriptor desc, bool isArra
564564
}
565565
}
566566

567-
public sealed override void RemoveOwnProperty(JsValue p)
567+
public sealed override void RemoveOwnProperty(JsValue property)
568568
{
569-
if (IsArrayIndex(p, out var index))
569+
if (IsArrayIndex(property, out var index))
570570
{
571571
Delete(index);
572572
}
573573

574-
if (p == CommonProperties.Length)
574+
if (CommonProperties.Length.Equals(property))
575575
{
576576
_length = null;
577577
}
578578

579-
base.RemoveOwnProperty(p);
579+
base.RemoveOwnProperty(property);
580580
}
581581

582582
[MethodImpl(MethodImplOptions.AggressiveInlining)]
583583
internal static bool IsArrayIndex(JsValue p, out uint index)
584584
{
585-
if (p is JsNumber number)
585+
if (p.IsNumber())
586586
{
587-
var value = number._value;
587+
var value = ((JsNumber) p)._value;
588588
var intValue = (uint) value;
589589
index = intValue;
590590
return value == intValue && intValue != uint.MaxValue;
591591
}
592592

593-
index = ParseArrayIndex(p.ToString());
593+
index = !p.IsSymbol() ? ParseArrayIndex(p.ToString()) : uint.MaxValue;
594594
return index != uint.MaxValue;
595595

596596
// 15.4 - Use an optimized version of the specification

Jint/Native/Function/FunctionInstance.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -126,15 +126,15 @@ internal sealed override IEnumerable<JsValue> GetInitialOwnStringPropertyKeys()
126126

127127
public override PropertyDescriptor GetOwnProperty(JsValue property)
128128
{
129-
if (property == CommonProperties.Prototype)
129+
if (CommonProperties.Prototype.Equals(property))
130130
{
131131
return _prototypeDescriptor ?? PropertyDescriptor.Undefined;
132132
}
133-
if (property == CommonProperties.Length)
133+
if (CommonProperties.Length.Equals(property))
134134
{
135135
return _length ?? PropertyDescriptor.Undefined;
136136
}
137-
if (property == CommonProperties.Name)
137+
if (CommonProperties.Name.Equals(property))
138138
{
139139
return _nameDescriptor ?? PropertyDescriptor.Undefined;
140140
}
@@ -144,15 +144,15 @@ public override PropertyDescriptor GetOwnProperty(JsValue property)
144144

145145
protected internal override void SetOwnProperty(JsValue property, PropertyDescriptor desc)
146146
{
147-
if (property == CommonProperties.Prototype)
147+
if (CommonProperties.Prototype.Equals(property))
148148
{
149149
_prototypeDescriptor = desc;
150150
}
151-
else if (property == CommonProperties.Length)
151+
else if (CommonProperties.Length.Equals(property))
152152
{
153153
_length = desc;
154154
}
155-
else if (property == CommonProperties.Name)
155+
else if (CommonProperties.Name.Equals(property))
156156
{
157157
_nameDescriptor = desc;
158158
}
@@ -164,15 +164,15 @@ protected internal override void SetOwnProperty(JsValue property, PropertyDescri
164164

165165
public override void RemoveOwnProperty(JsValue property)
166166
{
167-
if (property == CommonProperties.Prototype)
167+
if (CommonProperties.Prototype.Equals(property))
168168
{
169169
_prototypeDescriptor = null;
170170
}
171-
if (property == CommonProperties.Length)
171+
if (CommonProperties.Length.Equals(property))
172172
{
173173
_length = null;
174174
}
175-
if (property == CommonProperties.Name)
175+
if (CommonProperties.Name.Equals(property))
176176
{
177177
_nameDescriptor = null;
178178
}
@@ -401,7 +401,7 @@ public override IEnumerable<KeyValuePair<JsValue, PropertyDescriptor>> GetOwnPro
401401

402402
public override PropertyDescriptor GetOwnProperty(JsValue property)
403403
{
404-
if (property == CommonProperties.Constructor)
404+
if (CommonProperties.Constructor.Equals(property))
405405
{
406406
return _constructor ?? PropertyDescriptor.Undefined;
407407
}
@@ -411,7 +411,7 @@ public override PropertyDescriptor GetOwnProperty(JsValue property)
411411

412412
protected internal override void SetOwnProperty(JsValue property, PropertyDescriptor desc)
413413
{
414-
if (property == CommonProperties.Constructor)
414+
if (CommonProperties.Constructor.Equals(property))
415415
{
416416
_constructor = desc;
417417
}
@@ -423,7 +423,7 @@ protected internal override void SetOwnProperty(JsValue property, PropertyDescri
423423

424424
public override void RemoveOwnProperty(JsValue property)
425425
{
426-
if (property == CommonProperties.Constructor)
426+
if (CommonProperties.Constructor.Equals(property))
427427
{
428428
_constructor = null;
429429
}

Jint/Native/Iterator/IteratorResult.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,12 @@ public static IteratorResult CreateKeyValueIteratorPosition(Engine engine, JsVal
3232

3333
public override JsValue Get(JsValue property, JsValue receiver)
3434
{
35-
if (property == CommonProperties.Value)
35+
if (CommonProperties.Value.Equals(property))
3636
{
3737
return _value;
3838
}
3939

40-
if (property == CommonProperties.Done)
40+
if (CommonProperties.Done.Equals(property))
4141
{
4242
return _done;
4343
}

Jint/Native/JsString.cs

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Collections.Concurrent;
12
using System.Diagnostics;
23
using System.Text;
34
using Jint.Runtime;
@@ -12,27 +13,29 @@ public class JsString : JsValue, IEquatable<JsString>, IEquatable<string>
1213
private static readonly JsString[] _charToStringJsValue;
1314
private static readonly JsString[] _intToStringJsValue;
1415

15-
public static readonly JsString Empty = new JsString("");
16-
internal static readonly JsString NullString = new JsString("null");
17-
internal static readonly JsString UndefinedString = new JsString("undefined");
18-
internal static readonly JsString ObjectString = new JsString("object");
19-
internal static readonly JsString FunctionString = new JsString("function");
20-
internal static readonly JsString BooleanString = new JsString("boolean");
21-
internal static readonly JsString StringString = new JsString("string");
22-
internal static readonly JsString NumberString = new JsString("number");
23-
internal static readonly JsString BigIntString = new JsString("bigint");
24-
internal static readonly JsString SymbolString = new JsString("symbol");
25-
internal static readonly JsString DefaultString = new JsString("default");
26-
internal static readonly JsString NumberZeroString = new JsString("0");
27-
internal static readonly JsString NumberOneString = new JsString("1");
28-
internal static readonly JsString TrueString = new JsString("true");
29-
internal static readonly JsString FalseString = new JsString("false");
30-
internal static readonly JsString LengthString = new JsString("length");
31-
internal static readonly JsValue CommaString = new JsString(",");
16+
public static readonly JsString Empty;
17+
internal static readonly JsString NullString;
18+
internal static readonly JsString UndefinedString;
19+
internal static readonly JsString ObjectString;
20+
internal static readonly JsString FunctionString;
21+
internal static readonly JsString BooleanString;
22+
internal static readonly JsString StringString;
23+
internal static readonly JsString NumberString;
24+
internal static readonly JsString BigIntString;
25+
internal static readonly JsString SymbolString;
26+
internal static readonly JsString DefaultString;
27+
internal static readonly JsString NumberZeroString;
28+
internal static readonly JsString NumberOneString;
29+
internal static readonly JsString TrueString;
30+
internal static readonly JsString FalseString;
31+
internal static readonly JsString LengthString;
32+
internal static readonly JsValue CommaString;
3233

3334
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
3435
internal string _value;
3536

37+
private static ConcurrentDictionary<string, JsString> _stringCache;
38+
3639
static JsString()
3740
{
3841
_charToJsValue = new JsString[AsciiMax + 1];
@@ -49,6 +52,26 @@ static JsString()
4952
{
5053
_intToStringJsValue[i] = new JsString(TypeConverter.ToString(i));
5154
}
55+
56+
57+
_stringCache = new ConcurrentDictionary<string, JsString>();
58+
Empty = new JsString("", InternalTypes.String);
59+
NullString = CachedCreate("null");
60+
UndefinedString = CachedCreate("undefined");
61+
ObjectString = CachedCreate("object");
62+
FunctionString = CachedCreate("function");
63+
BooleanString = CachedCreate("boolean");
64+
StringString = CachedCreate("string");
65+
NumberString = CachedCreate("number");
66+
BigIntString = CachedCreate("bigint");
67+
SymbolString = CachedCreate("symbol");
68+
DefaultString = CachedCreate("default");
69+
NumberZeroString = CachedCreate("0");
70+
NumberOneString = CachedCreate("1");
71+
TrueString = CachedCreate("true");
72+
FalseString = CachedCreate("false");
73+
LengthString = CachedCreate("length");
74+
CommaString = CachedCreate(",");
5275
}
5376

5477
public JsString(string value) : this(value, InternalTypes.String)
@@ -146,6 +169,16 @@ internal static JsString Create(string value)
146169
return new JsString(value);
147170
}
148171

172+
internal static JsString CachedCreate(string value)
173+
{
174+
if (value.Length < 2)
175+
{
176+
return Create(value);
177+
}
178+
179+
return _stringCache.GetOrAdd(value, static x => new JsString(x));
180+
}
181+
149182
internal static JsString Create(char value)
150183
{
151184
var temp = _charToJsValue;

Jint/Native/Map/JsMap.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ public JsMap(Engine engine, Realm realm) : base(engine)
1818

1919
public override PropertyDescriptor GetOwnProperty(JsValue property)
2020
{
21-
if (property == CommonProperties.Size)
21+
if (CommonProperties.Size.Equals(property))
2222
{
2323
return new PropertyDescriptor(_map.Count, PropertyFlag.AllForbidden);
2424
}
@@ -28,7 +28,7 @@ public override PropertyDescriptor GetOwnProperty(JsValue property)
2828

2929
protected override bool TryGetProperty(JsValue property, [NotNullWhen(true)] out PropertyDescriptor? descriptor)
3030
{
31-
if (property == CommonProperties.Size)
31+
if (CommonProperties.Size.Equals(property))
3232
{
3333
descriptor = new PropertyDescriptor(_map.Count, PropertyFlag.AllForbidden);
3434
return true;

Jint/Native/Proxy/JsProxy.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public override JsValue Get(JsValue property, JsValue receiver)
128128
AssertTargetNotRevoked(property);
129129
var target = _target;
130130

131-
if (property == KeyFunctionRevoke || !TryCallHandler(TrapGet, new[] { target, TypeConverter.ToPropertyKey(property), receiver }, out var result))
131+
if (KeyFunctionRevoke.Equals(property) || !TryCallHandler(TrapGet, new[] { target, TypeConverter.ToPropertyKey(property), receiver }, out var result))
132132
{
133133
return target.Get(property, receiver);
134134
}

Jint/Native/RegExp/JsRegExp.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public string Flags
7878

7979
public override PropertyDescriptor GetOwnProperty(JsValue property)
8080
{
81-
if (property == PropertyLastIndex)
81+
if (PropertyLastIndex.Equals(property))
8282
{
8383
return _prototypeDescriptor ?? PropertyDescriptor.Undefined;
8484
}
@@ -88,7 +88,7 @@ public override PropertyDescriptor GetOwnProperty(JsValue property)
8888

8989
protected internal override void SetOwnProperty(JsValue property, PropertyDescriptor desc)
9090
{
91-
if (property == PropertyLastIndex)
91+
if (PropertyLastIndex.Equals(property))
9292
{
9393
_prototypeDescriptor = desc;
9494
return;

0 commit comments

Comments
 (0)