Skip to content

Commit 743368f

Browse files
committed
fix symbols; fix canonicalization of int64, -0
1 parent 24d0906 commit 743368f

File tree

7 files changed

+91
-39
lines changed

7 files changed

+91
-39
lines changed

lib/Runtime/Language/JavascriptConversion.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,15 +1522,21 @@ namespace Js
15221522
return NumberUtilities::TryToInt64(length);
15231523
}
15241524

1525+
// Lossy conversion means values are StrictEqual equivalent,
1526+
// but we cannot reconstruct the original value after canonicalization
1527+
// (e.g. -0 or an Int64Number object)
1528+
template <bool acceptLossyConversion>
15251529
Var JavascriptConversion::TryCanonicalizeAsSimpleVar(Var value)
15261530
{
15271531
TypeId typeId = JavascriptOperators::GetTypeId(value);
15281532
switch (typeId)
15291533
{
15301534
case TypeIds_Integer:
15311535
case TypeIds_Number:
1536+
case TypeIds_Int64Number:
1537+
case TypeIds_UInt64Number:
15321538
{
1533-
Var taggedInt = TryCanonicalizeAsTaggedInt<true>(value);
1539+
Var taggedInt = TryCanonicalizeAsTaggedInt<true, acceptLossyConversion>(value, typeId);
15341540
if (taggedInt)
15351541
{
15361542
return taggedInt;
@@ -1544,9 +1550,6 @@ namespace Js
15441550
}
15451551
case TypeIds_String:
15461552
case TypeIds_Symbol:
1547-
// TODO: try to canonicalize Int64/Uint64 to TaggedInt
1548-
case TypeIds_Int64Number:
1549-
case TypeIds_UInt64Number:
15501553
return nullptr;
15511554

15521555
default:

lib/Runtime/Language/JavascriptConversion.h

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

95-
template <bool allowNegOne>
95+
template <bool allowNegOne, bool acceptLossyConversion>
9696
static Var TryCanonicalizeAsTaggedInt(Var value);
97+
template <bool allowNegOne, bool acceptLossyConversion>
98+
static Var TryCanonicalizeAsTaggedInt(Var value, TypeId typeId);
99+
template <bool acceptLossyConversion>
97100
static Var TryCanonicalizeAsSimpleVar(Var value);
98101

99102
private:
103+
template <typename T, bool allowNegOne>
104+
static Var TryCanonicalizeIntHelper(T val);
105+
100106
static BOOL ToInt32Finite(double value, int32* result);
101107
template<bool zero>
102108
static bool SameValueCommon(Var aValue, Var bValue);

lib/Runtime/Language/JavascriptConversion.inl

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

206-
template <bool allowNegOne>
207-
inline Var JavascriptConversion::TryCanonicalizeAsTaggedInt(Var value)
206+
template <typename T, bool allowNegOne>
207+
static Var JavascriptConversion::TryCanonicalizeIntHelper(T val)
208208
{
209-
if (TaggedInt::Is(value))
209+
if (TaggedInt::IsOverflow(val))
210210
{
211-
return (allowNegOne || value != TaggedInt::ToVarUnchecked(-1))
212-
? value
213-
: nullptr;
211+
return nullptr;
214212
}
215213

216-
if (!JavascriptNumber::Is(value))
214+
if (!allowNegOne && val == -1)
217215
{
218216
return nullptr;
219217
}
220218

221-
double doubleVal = JavascriptNumber::GetValue(value);
222-
int32 intVal = 0;
219+
CompileAssert(sizeof(TaggedInt::k_nMinValue) <= sizeof(int));
220+
CompileAssert(sizeof(TaggedInt::k_nMaxValue) <= sizeof(int));
221+
222+
return TaggedInt::ToVarUnchecked((int)val);
223+
}
223224

224-
if (!JavascriptNumber::TryGetInt32Value<true>(doubleVal, &intVal))
225+
template <bool allowNegOne, bool allowLossyConversion>
226+
inline Var JavascriptConversion::TryCanonicalizeAsTaggedInt(Var value, TypeId typeId)
227+
{
228+
switch (typeId)
225229
{
226-
return nullptr;
227-
}
230+
case TypeIds_Integer:
231+
return (allowNegOne || value != TaggedInt::ToVarUnchecked(-1))
232+
? value
233+
: nullptr;
228234

229-
if (TaggedInt::IsOverflow(intVal))
235+
case TypeIds_Number:
230236
{
231-
return nullptr;
237+
double doubleVal = JavascriptNumber::GetValue(value);
238+
int32 intVal = 0;
239+
240+
if (!JavascriptNumber::TryGetInt32Value<allowLossyConversion>(doubleVal, &intVal))
241+
{
242+
return nullptr;
243+
}
244+
return TryCanonicalizeIntHelper<int32, allowNegOne>(intVal);
232245
}
246+
case TypeIds_Int64Number:
247+
{
248+
if (!allowLossyConversion)
249+
{
250+
return nullptr;
251+
}
252+
int64 int64Val = JavascriptInt64Number::UnsafeFromVar(value)->GetValue();
253+
254+
return TryCanonicalizeIntHelper<int64, allowNegOne>(int64Val);
233255

234-
if (!allowNegOne && intVal == -1)
256+
}
257+
case TypeIds_UInt64Number:
235258
{
259+
if (!allowLossyConversion)
260+
{
261+
return nullptr;
262+
}
263+
uint64 uint64Val = JavascriptUInt64Number::UnsafeFromVar(value)->GetValue();
264+
265+
return TryCanonicalizeIntHelper<uint64, allowNegOne>(uint64Val);
266+
}
267+
default:
236268
return nullptr;
237269
}
270+
}
238271

239-
return TaggedInt::ToVarUnchecked(intVal);
272+
template <bool allowNegOne, bool allowLossyConversion>
273+
inline Var JavascriptConversion::TryCanonicalizeAsTaggedInt(Var value)
274+
{
275+
TypeId typeId = JavascriptOperators::GetTypeId(value);
276+
return TryCanonicalizeAsTaggedInt<allowNegOne, allowLossyConversion>(value, typeId);
240277
}
241278

242279
} // namespace Js

lib/Runtime/Library/JavascriptMap.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -378,13 +378,13 @@ JavascriptMap::DeleteFromSimpleVarMap(Var value)
378378
{
379379
Assert(this->kind == MapKind::SimpleVarMap);
380380

381-
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar(value);
381+
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<true /* allowLossyConversion */>(value);
382382
if (!simpleVar)
383383
{
384384
return false;
385385
}
386386

387-
return this->DeleteFromVarMap<false>(simpleVar);
387+
return this->DeleteFromVarMap<false /* isComplex */>(simpleVar);
388388
}
389389

390390
bool
@@ -427,7 +427,7 @@ JavascriptMap::Get(Var key, Var* value)
427427
return true;
428428
}
429429
// If the key isn't in the map, check if the canonical value is
430-
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar(key);
430+
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<true /* allowLossyConversion */>(key);
431431
// If the simple var is the same as the original key, we know it isn't in the map
432432
if (!simpleVar || simpleVar == key)
433433
{
@@ -476,7 +476,7 @@ JavascriptMap::Has(Var key)
476476
return true;
477477
}
478478
// If the key isn't in the map, check if the canonical value is
479-
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar(key);
479+
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<true /* allowLossyConversion */>(key);
480480
// If the simple var is the same as the original key, we know it isn't in the map
481481
if (!simpleVar || simpleVar == key)
482482
{
@@ -517,7 +517,7 @@ void
517517
JavascriptMap::SetOnEmptyMap(Var key, Var value)
518518
{
519519
Assert(this->kind == MapKind::EmptyMap);
520-
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar(key);
520+
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<false /* allowLossyConversion */>(key);
521521
if (simpleVar)
522522
{
523523
SimpleVarDataMap* newSimpleMap = RecyclerNew(this->GetRecycler(), SimpleVarDataMap, this->GetRecycler());
@@ -548,7 +548,7 @@ JavascriptMap::TrySetOnSimpleVarMap(Var key, Var value)
548548
{
549549
Assert(this->kind == MapKind::SimpleVarMap);
550550

551-
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar(key);
551+
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<false /* allowLossyConversion */>(key);
552552
if (!simpleVar)
553553
{
554554
return false;

lib/Runtime/Library/JavascriptMap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace Js
2121
// An EmptyMap is a map containing no elements
2222
EmptyMap,
2323
// A SimpleVarMap is a map containing only Vars which are comparable by pointer, and don't require
24-
// pointer comparison
24+
// value comparison
2525
//
2626
// Addition of a Var that is not comparable by pointer value causes the set to be promoted to a ComplexVarSet
2727
SimpleVarMap,

lib/Runtime/Library/JavascriptSet.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,7 @@ JavascriptSet::AddToEmptySet(Var value)
328328
{
329329
Assert(this->kind == SetKind::EmptySet);
330330
// We cannot store an int with value -1 inside of a bit vector
331-
Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false>(value);
331+
Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false /* allowNegOne */, false /* allowLossyConversion */>(value);
332332
if (taggedInt)
333333
{
334334
int32 intVal = TaggedInt::ToInt32(taggedInt);
@@ -343,7 +343,7 @@ JavascriptSet::AddToEmptySet(Var value)
343343
return;
344344
}
345345

346-
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar(value);
346+
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<false /* allowLossyConversion */>(value);
347347
if (simpleVar)
348348
{
349349
SimpleVarDataSet* newSimpleSet = RecyclerNew(this->GetRecycler(), SimpleVarDataSet, this->GetRecycler());
@@ -369,7 +369,7 @@ bool
369369
JavascriptSet::TryAddToIntSet(Var value)
370370
{
371371
Assert(this->kind == SetKind::IntSet);
372-
Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false>(value);
372+
Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false /* allowNegOne */, false /* allowLossyConversion */>(value);
373373
if (!taggedInt)
374374
{
375375
return false;
@@ -387,7 +387,7 @@ bool
387387
JavascriptSet::TryAddToSimpleVarSet(Var value)
388388
{
389389
Assert(this->kind == SetKind::SimpleVarSet);
390-
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar(value);
390+
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<false /* allowLossyConversion */>(value);
391391
if (!simpleVar)
392392
{
393393
return false;
@@ -432,7 +432,7 @@ JavascriptSet::Add(Var value)
432432
return;
433433
}
434434

435-
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar(value);
435+
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<false /* allowLossyConversion */>(value);
436436
if (simpleVar)
437437
{
438438
this->PromoteToSimpleVarSet();
@@ -490,7 +490,7 @@ bool
490490
JavascriptSet::IsInIntSet(Var value)
491491
{
492492
Assert(this->kind == SetKind::IntSet);
493-
Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false>(value);
493+
Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false /* allowNegOne */, true /* allowLossyConversion */>(value);
494494
if (!taggedInt)
495495
{
496496
return false;
@@ -520,7 +520,7 @@ bool
520520
JavascriptSet::DeleteFromSimpleVarSet(Var value)
521521
{
522522
Assert(this->kind == SetKind::SimpleVarSet);
523-
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar(value);
523+
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<true /* allowLossyConversion */>(value);
524524
if (!simpleVar)
525525
{
526526
return false;
@@ -553,7 +553,7 @@ bool JavascriptSet::Delete(Var value)
553553
return this->DeleteFromSimpleVarSet(value);
554554

555555
case SetKind::ComplexVarSet:
556-
return this->DeleteFromVarSet<true>(value);
556+
return this->DeleteFromVarSet<true /* isComplex */>(value);
557557

558558
default:
559559
Assume(UNREACHED);
@@ -571,7 +571,7 @@ bool JavascriptSet::Has(Var value)
571571

572572
case SetKind::IntSet:
573573
{
574-
Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false>(value);
574+
Var taggedInt = JavascriptConversion::TryCanonicalizeAsTaggedInt<false /* allowNegOne */, true /* allowLossyConversion */ >(value);
575575
if (!taggedInt)
576576
{
577577
return false;
@@ -588,7 +588,7 @@ bool JavascriptSet::Has(Var value)
588588
return true;
589589
}
590590
// If the value isn't in the set, check if the canonical value is
591-
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar(value);
591+
Var simpleVar = JavascriptConversion::TryCanonicalizeAsSimpleVar<true /* allowLossyConversion */>(value);
592592
// If the simple value is the same as the original value, we know it isn't in the set
593593
if (!simpleVar || simpleVar == value)
594594
{

lib/Runtime/Library/SameValueComparer.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,16 @@ namespace Js
8585

8686
case TypeIds_String:
8787
{
88-
JavascriptString* v = JavascriptString::FromVar(i);
88+
JavascriptString* v = JavascriptString::UnsafeFromVar(i);
8989
return JsUtil::CharacterBuffer<WCHAR>::StaticGetHashCode(v->GetString(), v->GetLength());
9090
}
9191

92+
case TypeIds_Symbol:
93+
{
94+
JavascriptSymbol* sym = JavascriptSymbol::UnsafeFromVar(i);
95+
return sym->GetValue()->GetHashCode();
96+
}
97+
9298
default:
9399
return RecyclerPointerComparer<Var>::GetHashCode(i);
94100
}

0 commit comments

Comments
 (0)