Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add specialized types of Sets and Maps #4816

Merged
merged 7 commits into from
Mar 20, 2018
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
2 changes: 1 addition & 1 deletion lib/Backend/JITRecyclableObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class JITJavascriptString : JITRecyclableObject
return m_charLength;
}

static bool Equals(Js::Var aLeft, Js::Var aRight)
static bool Equals(JITJavascriptString* aLeft, JITJavascriptString* aRight)
{
return Js::JavascriptStringHelpers<JITJavascriptString>::Equals(aLeft, aRight);
}
Expand Down
23 changes: 12 additions & 11 deletions lib/Runtime/Language/JavascriptConversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,19 @@ namespace Js
template<bool zero>
bool JavascriptConversion::SameValueCommon(Var aLeft, Var aRight)
{
if (aLeft == aRight)
{
return true;
}

TypeId leftType = JavascriptOperators::GetTypeId(aLeft);
TypeId rightType = JavascriptOperators::GetTypeId(aRight);

if (JavascriptOperators::IsUndefinedOrNullType(leftType))
{
return leftType == rightType;
return false;
Copy link
Contributor

@akroshg akroshg Mar 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if both values are undefined but belonged to different script context? #Pending

Copy link
Contributor Author

@MikeHolman MikeHolman Mar 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have thought they should be marshalled to correct script context by here? If that's not true, then Booleans are broken already in the existing code. #Pending

}

TypeId rightType = JavascriptOperators::GetTypeId(aRight);
double dblLeft, dblRight;

switch (leftType)
Expand All @@ -70,7 +75,7 @@ namespace Js
switch (rightType)
{
case TypeIds_Integer:
return aLeft == aRight;
return false;
case TypeIds_Number:
dblLeft = TaggedInt::ToDouble(aLeft);
dblRight = JavascriptNumber::GetValue(aRight);
Expand Down Expand Up @@ -181,17 +186,12 @@ namespace Js
}
break;
case TypeIds_Boolean:
switch (rightType)
{
case TypeIds_Boolean:
return aLeft == aRight;
}
break;
return false;
case TypeIds_String:
switch (rightType)
{
case TypeIds_String:
return JavascriptString::Equals(aLeft, aRight);
return JavascriptString::Equals(JavascriptString::UnsafeFromVar(aLeft), JavascriptString::UnsafeFromVar(aRight));
}
break;
case TypeIds_Symbol:
Expand All @@ -208,7 +208,7 @@ namespace Js
default:
break;
}
return aLeft == aRight;
return false;
}

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

return NumberUtilities::TryToInt64(length);
}

} // namespace Js
10 changes: 10 additions & 0 deletions lib/Runtime/Language/JavascriptConversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,17 @@ namespace Js {
static double LongToDouble(__int64 aValue);
static double ULongToDouble(unsigned __int64 aValue);

template <bool allowNegOne, bool allowLossyConversion>
static Var TryCanonicalizeAsTaggedInt(Var value);
template <bool allowNegOne, bool allowLossyConversion>
static Var TryCanonicalizeAsTaggedInt(Var value, TypeId typeId);
template <bool allowLossyConversion>
static Var TryCanonicalizeAsSimpleVar(Var value);

private:
template <typename T, bool allowNegOne>
static Var TryCanonicalizeIntHelper(T val);

static BOOL ToInt32Finite(double value, int32* result);
template<bool zero>
static bool SameValueCommon(Var aValue, Var bValue);
Expand Down
105 changes: 105 additions & 0 deletions lib/Runtime/Language/JavascriptConversion.inl
Original file line number Diff line number Diff line change
Expand Up @@ -203,4 +203,109 @@ namespace Js {
return SameValueCommon<true>(aValue, bValue);
}

template <typename T, bool allowNegOne>
inline Var JavascriptConversion::TryCanonicalizeIntHelper(T val)
{
if (TaggedInt::IsOverflow(val))
{
return nullptr;
}

if (!allowNegOne && val == -1)
{
return nullptr;
}

return TaggedInt::ToVarUnchecked((int)val);
}

template <bool allowNegOne, bool allowLossyConversion>
inline Var JavascriptConversion::TryCanonicalizeAsTaggedInt(Var value, TypeId typeId)
{
switch (typeId)
{
case TypeIds_Integer:
return (allowNegOne || value != TaggedInt::ToVarUnchecked(-1))
? value
: nullptr;

case TypeIds_Number:
{
double doubleVal = JavascriptNumber::GetValue(value);
int32 intVal = 0;

if (!JavascriptNumber::TryGetInt32Value<allowLossyConversion>(doubleVal, &intVal))
{
return nullptr;
}
return TryCanonicalizeIntHelper<int32, allowNegOne>(intVal);
}
case TypeIds_Int64Number:
{
if (!allowLossyConversion)
{
return nullptr;
}
int64 int64Val = JavascriptInt64Number::UnsafeFromVar(value)->GetValue();

return TryCanonicalizeIntHelper<int64, allowNegOne>(int64Val);

}
case TypeIds_UInt64Number:
{
if (!allowLossyConversion)
{
return nullptr;
}
uint64 uint64Val = JavascriptUInt64Number::UnsafeFromVar(value)->GetValue();

return TryCanonicalizeIntHelper<uint64, allowNegOne>(uint64Val);
}
default:
return nullptr;
}
}

template <bool allowNegOne, bool allowLossyConversion>
inline Var JavascriptConversion::TryCanonicalizeAsTaggedInt(Var value)
{
TypeId typeId = JavascriptOperators::GetTypeId(value);
return TryCanonicalizeAsTaggedInt<allowNegOne, allowLossyConversion>(value, typeId);
}

// Lossy conversion means values are StrictEqual equivalent,
// but we cannot reconstruct the original value after canonicalization
// (e.g. -0 or an Int64Number object)
template <bool allowLossyConversion>
inline Var JavascriptConversion::TryCanonicalizeAsSimpleVar(Var value)
{
TypeId typeId = JavascriptOperators::GetTypeId(value);
switch (typeId)
{
case TypeIds_Integer:
case TypeIds_Number:
case TypeIds_Int64Number:
case TypeIds_UInt64Number:
{
Var taggedInt = TryCanonicalizeAsTaggedInt<true, allowLossyConversion>(value, typeId);
if (taggedInt)
{
return taggedInt;
}

#if FLOATVAR
return value;
#else
return nullptr;
#endif
}
case TypeIds_String:
case TypeIds_Symbol:
return nullptr;

default:
return value;
}
}

} // namespace Js
16 changes: 8 additions & 8 deletions lib/Runtime/Language/JavascriptOperators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -746,14 +746,14 @@ namespace Js
return dblLeft < dblRight;
}

BOOL JavascriptOperators::StrictEqualString(Var aLeft, Var aRight)
BOOL JavascriptOperators::StrictEqualString(Var aLeft, JavascriptString* aRight)
{
Assert(JavascriptOperators::GetTypeId(aRight) == TypeIds_String);

if (JavascriptOperators::GetTypeId(aLeft) != TypeIds_String)
JavascriptString* leftStr = TryFromVar<JavascriptString>(aLeft);
if (!leftStr)
{
return false;

return JavascriptString::Equals(aLeft, aRight);
}
return JavascriptString::Equals(leftStr, aRight);
}

BOOL JavascriptOperators::StrictEqualEmptyString(Var aLeft)
Expand Down Expand Up @@ -785,7 +785,7 @@ namespace Js
switch (rightType)
{
case TypeIds_String:
return JavascriptString::Equals(aLeft, aRight);
return JavascriptString::Equals(JavascriptString::UnsafeFromVar(aLeft), JavascriptString::UnsafeFromVar(aRight));
}
return FALSE;
case TypeIds_Integer:
Expand Down Expand Up @@ -5188,7 +5188,7 @@ namespace Js
return JavascriptBoolean::ToVar(JavascriptOperators::StrictEqual(a, b, scriptContext), scriptContext);
}

Var JavascriptOperators::OP_CmSrEq_String(Var a, Var b, ScriptContext *scriptContext)
Var JavascriptOperators::OP_CmSrEq_String(Var a, JavascriptString* b, ScriptContext *scriptContext)
{
return JavascriptBoolean::ToVar(JavascriptOperators::StrictEqualString(a, b), scriptContext);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/Runtime/Language/JavascriptOperators.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ namespace Js
static BOOL LessEqual(Var aLeft, Var aRight,ScriptContext* scriptContext);
static BOOL NotEqual(Var aLeft, Var aRight,ScriptContext* scriptContext);
static BOOL StrictEqual(Var aLeft, Var aRight,ScriptContext* scriptContext);
static BOOL StrictEqualString(Var aLeft, Var aRight);
static BOOL StrictEqualString(Var aLeft, JavascriptString* aRight);
static BOOL StrictEqualEmptyString(Var aLeft);
static BOOL NotStrictEqual(Var aLeft, Var aRight,ScriptContext* scriptContext);

Expand Down Expand Up @@ -400,7 +400,7 @@ namespace Js
static Var OP_CmEq_A(Js::Var a,Js::Var b,ScriptContext* scriptContext);
static Var OP_CmNeq_A(Js::Var a,Js::Var b,ScriptContext* scriptContext);
static Var OP_CmSrEq_A(Js::Var a,Js::Var b,ScriptContext* scriptContext);
static Var OP_CmSrEq_String(Var a, Var b, ScriptContext *scriptContext);
static Var OP_CmSrEq_String(Var a, JavascriptString* b, ScriptContext *scriptContext);
static Var OP_CmSrEq_EmptyString(Var a, ScriptContext *scriptContext);
static Var OP_CmSrNeq_A(Js::Var a,Js::Var b,ScriptContext* scriptContext);
static Var OP_CmLt_A(Js::Var a,Js::Var b,ScriptContext* scriptContext);
Expand Down
2 changes: 1 addition & 1 deletion lib/Runtime/Library/JavascriptLibrary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5432,7 +5432,7 @@ namespace Js
AssertOrFailFast(hasRight);

// If the strings at this index are not equal, the callsite objects are not equal.
if (!Js::JavascriptString::Equals(varLeft, varRight))
if (!Js::JavascriptString::Equals(JavascriptString::FromVar(varLeft), JavascriptString::FromVar(varRight)))
{
return false;
}
Expand Down
Loading