Skip to content

Commit e8c4ae6

Browse files
committed
[MERGE #4816 @MikeHolman] Add specialized types of Sets and Maps
Merge pull request #4816 from MikeHolman:setopt_pr This change separates sets into three different types: Int, Simple, and Complex. Int sets are sets which contain only int values. They are represented with a bit vector. Simple sets contain values that are comparable by pointer alone, and use a normal dictionary. Complex sets are sets that need full value comparison, and use a dictionary with a custom comparator. I also added two kinds of maps, Simple and Complex, which function the same as simple and complex sets. Improves perf of ARES-6 by 6% and VueJS by about 4%.
2 parents adf0ecb + f9639b7 commit e8c4ae6

16 files changed

+1332
-586
lines changed

lib/Backend/JITRecyclableObject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class JITJavascriptString : JITRecyclableObject
3838
return m_charLength;
3939
}
4040

41-
static bool Equals(Js::Var aLeft, Js::Var aRight)
41+
static bool Equals(JITJavascriptString* aLeft, JITJavascriptString* aRight)
4242
{
4343
return Js::JavascriptStringHelpers<JITJavascriptString>::Equals(aLeft, aRight);
4444
}

lib/Runtime/Language/JavascriptConversion.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,19 @@ namespace Js
5454
template<bool zero>
5555
bool JavascriptConversion::SameValueCommon(Var aLeft, Var aRight)
5656
{
57+
if (aLeft == aRight)
58+
{
59+
return true;
60+
}
61+
5762
TypeId leftType = JavascriptOperators::GetTypeId(aLeft);
58-
TypeId rightType = JavascriptOperators::GetTypeId(aRight);
5963

6064
if (JavascriptOperators::IsUndefinedOrNullType(leftType))
6165
{
62-
return leftType == rightType;
66+
return false;
6367
}
6468

69+
TypeId rightType = JavascriptOperators::GetTypeId(aRight);
6570
double dblLeft, dblRight;
6671

6772
switch (leftType)
@@ -70,7 +75,7 @@ namespace Js
7075
switch (rightType)
7176
{
7277
case TypeIds_Integer:
73-
return aLeft == aRight;
78+
return false;
7479
case TypeIds_Number:
7580
dblLeft = TaggedInt::ToDouble(aLeft);
7681
dblRight = JavascriptNumber::GetValue(aRight);
@@ -181,17 +186,12 @@ namespace Js
181186
}
182187
break;
183188
case TypeIds_Boolean:
184-
switch (rightType)
185-
{
186-
case TypeIds_Boolean:
187-
return aLeft == aRight;
188-
}
189-
break;
189+
return false;
190190
case TypeIds_String:
191191
switch (rightType)
192192
{
193193
case TypeIds_String:
194-
return JavascriptString::Equals(aLeft, aRight);
194+
return JavascriptString::Equals(JavascriptString::UnsafeFromVar(aLeft), JavascriptString::UnsafeFromVar(aRight));
195195
}
196196
break;
197197
case TypeIds_Symbol:
@@ -208,7 +208,7 @@ namespace Js
208208
default:
209209
break;
210210
}
211-
return aLeft == aRight;
211+
return false;
212212
}
213213

214214
template bool JavascriptConversion::SameValueCommon<false>(Var aLeft, Var aRight);
@@ -1521,4 +1521,5 @@ namespace Js
15211521

15221522
return NumberUtilities::TryToInt64(length);
15231523
}
1524+
15241525
} // namespace Js

lib/Runtime/Language/JavascriptConversion.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,17 @@ namespace Js {
9292
static double LongToDouble(__int64 aValue);
9393
static double ULongToDouble(unsigned __int64 aValue);
9494

95+
template <bool allowNegOne, bool allowLossyConversion>
96+
static Var TryCanonicalizeAsTaggedInt(Var value);
97+
template <bool allowNegOne, bool allowLossyConversion>
98+
static Var TryCanonicalizeAsTaggedInt(Var value, TypeId typeId);
99+
template <bool allowLossyConversion>
100+
static Var TryCanonicalizeAsSimpleVar(Var value);
101+
95102
private:
103+
template <typename T, bool allowNegOne>
104+
static Var TryCanonicalizeIntHelper(T val);
105+
96106
static BOOL ToInt32Finite(double value, int32* result);
97107
template<bool zero>
98108
static bool SameValueCommon(Var aValue, Var bValue);

lib/Runtime/Language/JavascriptConversion.inl

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,109 @@ namespace Js {
203203
return SameValueCommon<true>(aValue, bValue);
204204
}
205205

206+
template <typename T, bool allowNegOne>
207+
inline Var JavascriptConversion::TryCanonicalizeIntHelper(T val)
208+
{
209+
if (TaggedInt::IsOverflow(val))
210+
{
211+
return nullptr;
212+
}
213+
214+
if (!allowNegOne && val == -1)
215+
{
216+
return nullptr;
217+
}
218+
219+
return TaggedInt::ToVarUnchecked((int)val);
220+
}
221+
222+
template <bool allowNegOne, bool allowLossyConversion>
223+
inline Var JavascriptConversion::TryCanonicalizeAsTaggedInt(Var value, TypeId typeId)
224+
{
225+
switch (typeId)
226+
{
227+
case TypeIds_Integer:
228+
return (allowNegOne || value != TaggedInt::ToVarUnchecked(-1))
229+
? value
230+
: nullptr;
231+
232+
case TypeIds_Number:
233+
{
234+
double doubleVal = JavascriptNumber::GetValue(value);
235+
int32 intVal = 0;
236+
237+
if (!JavascriptNumber::TryGetInt32Value<allowLossyConversion>(doubleVal, &intVal))
238+
{
239+
return nullptr;
240+
}
241+
return TryCanonicalizeIntHelper<int32, allowNegOne>(intVal);
242+
}
243+
case TypeIds_Int64Number:
244+
{
245+
if (!allowLossyConversion)
246+
{
247+
return nullptr;
248+
}
249+
int64 int64Val = JavascriptInt64Number::UnsafeFromVar(value)->GetValue();
250+
251+
return TryCanonicalizeIntHelper<int64, allowNegOne>(int64Val);
252+
253+
}
254+
case TypeIds_UInt64Number:
255+
{
256+
if (!allowLossyConversion)
257+
{
258+
return nullptr;
259+
}
260+
uint64 uint64Val = JavascriptUInt64Number::UnsafeFromVar(value)->GetValue();
261+
262+
return TryCanonicalizeIntHelper<uint64, allowNegOne>(uint64Val);
263+
}
264+
default:
265+
return nullptr;
266+
}
267+
}
268+
269+
template <bool allowNegOne, bool allowLossyConversion>
270+
inline Var JavascriptConversion::TryCanonicalizeAsTaggedInt(Var value)
271+
{
272+
TypeId typeId = JavascriptOperators::GetTypeId(value);
273+
return TryCanonicalizeAsTaggedInt<allowNegOne, allowLossyConversion>(value, typeId);
274+
}
275+
276+
// Lossy conversion means values are StrictEqual equivalent,
277+
// but we cannot reconstruct the original value after canonicalization
278+
// (e.g. -0 or an Int64Number object)
279+
template <bool allowLossyConversion>
280+
inline Var JavascriptConversion::TryCanonicalizeAsSimpleVar(Var value)
281+
{
282+
TypeId typeId = JavascriptOperators::GetTypeId(value);
283+
switch (typeId)
284+
{
285+
case TypeIds_Integer:
286+
case TypeIds_Number:
287+
case TypeIds_Int64Number:
288+
case TypeIds_UInt64Number:
289+
{
290+
Var taggedInt = TryCanonicalizeAsTaggedInt<true, allowLossyConversion>(value, typeId);
291+
if (taggedInt)
292+
{
293+
return taggedInt;
294+
}
295+
296+
#if FLOATVAR
297+
return value;
298+
#else
299+
return nullptr;
300+
#endif
301+
}
302+
case TypeIds_String:
303+
case TypeIds_Symbol:
304+
return nullptr;
305+
306+
default:
307+
return value;
308+
}
309+
}
310+
206311
} // namespace Js

lib/Runtime/Language/JavascriptOperators.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -746,14 +746,14 @@ namespace Js
746746
return dblLeft < dblRight;
747747
}
748748

749-
BOOL JavascriptOperators::StrictEqualString(Var aLeft, Var aRight)
749+
BOOL JavascriptOperators::StrictEqualString(Var aLeft, JavascriptString* aRight)
750750
{
751-
Assert(JavascriptOperators::GetTypeId(aRight) == TypeIds_String);
752-
753-
if (JavascriptOperators::GetTypeId(aLeft) != TypeIds_String)
751+
JavascriptString* leftStr = TryFromVar<JavascriptString>(aLeft);
752+
if (!leftStr)
753+
{
754754
return false;
755-
756-
return JavascriptString::Equals(aLeft, aRight);
755+
}
756+
return JavascriptString::Equals(leftStr, aRight);
757757
}
758758

759759
BOOL JavascriptOperators::StrictEqualEmptyString(Var aLeft)
@@ -785,7 +785,7 @@ namespace Js
785785
switch (rightType)
786786
{
787787
case TypeIds_String:
788-
return JavascriptString::Equals(aLeft, aRight);
788+
return JavascriptString::Equals(JavascriptString::UnsafeFromVar(aLeft), JavascriptString::UnsafeFromVar(aRight));
789789
}
790790
return FALSE;
791791
case TypeIds_Integer:
@@ -5188,7 +5188,7 @@ namespace Js
51885188
return JavascriptBoolean::ToVar(JavascriptOperators::StrictEqual(a, b, scriptContext), scriptContext);
51895189
}
51905190

5191-
Var JavascriptOperators::OP_CmSrEq_String(Var a, Var b, ScriptContext *scriptContext)
5191+
Var JavascriptOperators::OP_CmSrEq_String(Var a, JavascriptString* b, ScriptContext *scriptContext)
51925192
{
51935193
return JavascriptBoolean::ToVar(JavascriptOperators::StrictEqualString(a, b), scriptContext);
51945194
}

lib/Runtime/Language/JavascriptOperators.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ namespace Js
150150
static BOOL LessEqual(Var aLeft, Var aRight,ScriptContext* scriptContext);
151151
static BOOL NotEqual(Var aLeft, Var aRight,ScriptContext* scriptContext);
152152
static BOOL StrictEqual(Var aLeft, Var aRight,ScriptContext* scriptContext);
153-
static BOOL StrictEqualString(Var aLeft, Var aRight);
153+
static BOOL StrictEqualString(Var aLeft, JavascriptString* aRight);
154154
static BOOL StrictEqualEmptyString(Var aLeft);
155155
static BOOL NotStrictEqual(Var aLeft, Var aRight,ScriptContext* scriptContext);
156156

@@ -400,7 +400,7 @@ namespace Js
400400
static Var OP_CmEq_A(Js::Var a,Js::Var b,ScriptContext* scriptContext);
401401
static Var OP_CmNeq_A(Js::Var a,Js::Var b,ScriptContext* scriptContext);
402402
static Var OP_CmSrEq_A(Js::Var a,Js::Var b,ScriptContext* scriptContext);
403-
static Var OP_CmSrEq_String(Var a, Var b, ScriptContext *scriptContext);
403+
static Var OP_CmSrEq_String(Var a, JavascriptString* b, ScriptContext *scriptContext);
404404
static Var OP_CmSrEq_EmptyString(Var a, ScriptContext *scriptContext);
405405
static Var OP_CmSrNeq_A(Js::Var a,Js::Var b,ScriptContext* scriptContext);
406406
static Var OP_CmLt_A(Js::Var a,Js::Var b,ScriptContext* scriptContext);

lib/Runtime/Library/JavascriptLibrary.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5432,7 +5432,7 @@ namespace Js
54325432
AssertOrFailFast(hasRight);
54335433

54345434
// If the strings at this index are not equal, the callsite objects are not equal.
5435-
if (!Js::JavascriptString::Equals(varLeft, varRight))
5435+
if (!Js::JavascriptString::Equals(JavascriptString::FromVar(varLeft), JavascriptString::FromVar(varRight)))
54365436
{
54375437
return false;
54385438
}

0 commit comments

Comments
 (0)