Skip to content

Commit 10a6930

Browse files
committedSep 25, 2018
[MERGE #5727 @sharmasuraj0123] Fixes #5201: Implemented StringTemplate Caching based on location in source Code.
Merge pull request #5727 from sharmasuraj0123:StringTemplateCaching Changed the earlier implementation of caching the StringTemplates based on Raw String Literals to their location in the source code. Old Behavior: ```js function getCallsite(c) { return c; } function getFooCallsite() { return getCallsite`foo`; } print(getFooCallsite() === getFooCallsite()); // true print(getCallsite`foo` === getCallsite`foo`); // true print(getCallsite`foo` === eval('getCallsite`foo`')); // true ``` New Behavior: ```js function getCallsite(c) { return c; } function getFooCallsite() { return getCallsite`foo`; } print(getFooCallsite() === getFooCallsite()); // true print(getCallsite`foo` === getCallsite`foo`); // false print(getCallsite`foo` === eval('getCallsite`foo`')); // false ``` Deleted the added mapping that would compare and ensure that the two callsite objects are equal based on their raw String literals. Now it store every diferent pnode object it comes accross and assigns it a register. Fixes #5201
2 parents 6a9b83b + f8023f7 commit 10a6930

File tree

6 files changed

+58
-472
lines changed

6 files changed

+58
-472
lines changed
 

‎lib/Runtime/ByteCode/ByteCodeEmitter.cpp

+6-13
Original file line numberDiff line numberDiff line change
@@ -5692,20 +5692,13 @@ void ByteCodeGenerator::RecordAllStringTemplateCallsiteConstants(FuncInfo* funcI
56925692
funcInfo->stringTemplateCallsiteRegisterMap.Map([byteCodeFunction](ParseNodePtr pnode, Js::RegSlot location)
56935693
{
56945694
Js::ScriptContext* scriptContext = byteCodeFunction->GetScriptContext();
5695-
Js::JavascriptLibrary* library = scriptContext->GetLibrary();
5696-
Js::RecyclableObject* callsiteObject = library->TryGetStringTemplateCallsiteObject(pnode);
5697-
5698-
if (callsiteObject == nullptr)
5699-
{
5700-
Js::RecyclableObject* rawArray = ByteCodeGenerator::BuildArrayFromStringList(pnode->AsParseNodeStrTemplate()->pnodeStringRawLiterals, pnode->AsParseNodeStrTemplate()->countStringLiterals, scriptContext);
5701-
rawArray->Freeze();
5702-
5703-
callsiteObject = ByteCodeGenerator::BuildArrayFromStringList(pnode->AsParseNodeStrTemplate()->pnodeStringLiterals, pnode->AsParseNodeStrTemplate()->countStringLiterals, scriptContext);
5704-
callsiteObject->SetPropertyWithAttributes(Js::PropertyIds::raw, rawArray, PropertyNone, nullptr);
5705-
callsiteObject->Freeze();
5695+
5696+
Js::RecyclableObject* rawArray = ByteCodeGenerator::BuildArrayFromStringList(pnode->AsParseNodeStrTemplate()->pnodeStringRawLiterals, pnode->AsParseNodeStrTemplate()->countStringLiterals, scriptContext);
5697+
rawArray->Freeze();
57065698

5707-
library->AddStringTemplateCallsiteObject(callsiteObject);
5708-
}
5699+
Js::RecyclableObject* callsiteObject = ByteCodeGenerator::BuildArrayFromStringList(pnode->AsParseNodeStrTemplate()->pnodeStringLiterals, pnode->AsParseNodeStrTemplate()->countStringLiterals, scriptContext);
5700+
callsiteObject->SetPropertyWithAttributes(Js::PropertyIds::raw, rawArray, PropertyNone, nullptr);
5701+
callsiteObject->Freeze();
57095702

57105703
byteCodeFunction->RecordConstant(byteCodeFunction->MapRegSlot(location), callsiteObject);
57115704
});

‎lib/Runtime/ByteCode/ByteCodeSerializer.cpp

+1-10
Original file line numberDiff line numberDiff line change
@@ -3210,16 +3210,7 @@ class ByteCodeBufferReader
32103210
callsite->SetPropertyWithAttributes(Js::PropertyIds::raw, rawArray, PropertyNone, nullptr);
32113211
callsite->Freeze();
32123212

3213-
JavascriptLibrary* library = scriptContext->GetLibrary();
3214-
3215-
var = library->TryGetStringTemplateCallsiteObject(callsite);
3216-
3217-
if (var == nullptr)
3218-
{
3219-
library->AddStringTemplateCallsiteObject(callsite);
3220-
var = callsite;
3221-
}
3222-
3213+
var = callsite;
32233214
LEAVE_PINNED_SCOPE();
32243215

32253216
return current;

‎lib/Runtime/ByteCode/FuncInfo.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ class FuncInfo
146146
typedef JsUtil::BaseDictionary<double,Js::RegSlot, ArenaAllocator, PrimeSizePolicy> DoubleRegisterMap;
147147
DoubleRegisterMap doubleConstantToRegister; // maps double constant to register
148148

149-
typedef JsUtil::BaseDictionary<ParseNodePtr, Js::RegSlot, ArenaAllocator, PowerOf2SizePolicy, Js::StringTemplateCallsiteObjectComparer> StringTemplateCallsiteRegisterMap;
149+
typedef JsUtil::BaseDictionary<ParseNodePtr, Js::RegSlot, ArenaAllocator, PowerOf2SizePolicy> StringTemplateCallsiteRegisterMap;
150150
StringTemplateCallsiteRegisterMap stringTemplateCallsiteRegisterMap; // maps string template callsite constant to register
151151

152152
Scope *paramScope; // top level scope for parameter default values

‎lib/Runtime/Library/JavascriptLibrary.cpp

+2-341
Original file line numberDiff line numberDiff line change
@@ -5253,63 +5253,7 @@ namespace Js
52535253
#endif
52545254
return function;
52555255
}
5256-
5257-
void JavascriptLibrary::EnsureStringTemplateCallsiteObjectList()
5258-
{
5259-
if (this->stringTemplateCallsiteObjectList == nullptr)
5260-
{
5261-
this->stringTemplateCallsiteObjectList = RecyclerNew(GetRecycler(), StringTemplateCallsiteObjectList, GetRecycler());
5262-
}
5263-
}
5264-
5265-
void JavascriptLibrary::AddStringTemplateCallsiteObject(RecyclableObject* callsite)
5266-
{
5267-
this->EnsureStringTemplateCallsiteObjectList();
5268-
5269-
RecyclerWeakReference<RecyclableObject>* callsiteRef = this->GetRecycler()->CreateWeakReferenceHandle<RecyclableObject>(callsite);
5270-
5271-
this->stringTemplateCallsiteObjectList->Item(callsiteRef);
5272-
}
5273-
5274-
RecyclableObject* JavascriptLibrary::TryGetStringTemplateCallsiteObject(ParseNodePtr pnode)
5275-
{
5276-
this->EnsureStringTemplateCallsiteObjectList();
5277-
5278-
RecyclerWeakReference<RecyclableObject>* callsiteRef = this->stringTemplateCallsiteObjectList->LookupWithKey(pnode);
5279-
5280-
if (callsiteRef)
5281-
{
5282-
RecyclableObject* callsite = callsiteRef->Get();
5283-
5284-
if (callsite)
5285-
{
5286-
return callsite;
5287-
}
5288-
}
5289-
5290-
return nullptr;
5291-
}
5292-
5293-
RecyclableObject* JavascriptLibrary::TryGetStringTemplateCallsiteObject(RecyclableObject* callsite)
5294-
{
5295-
this->EnsureStringTemplateCallsiteObjectList();
5296-
5297-
RecyclerWeakReference<RecyclableObject>* callsiteRef = this->GetRecycler()->CreateWeakReferenceHandle<RecyclableObject>(callsite);
5298-
RecyclerWeakReference<RecyclableObject>* existingCallsiteRef = this->stringTemplateCallsiteObjectList->LookupWithKey(callsiteRef);
5299-
5300-
if (existingCallsiteRef)
5301-
{
5302-
RecyclableObject* existingCallsite = existingCallsiteRef->Get();
5303-
5304-
if (existingCallsite)
5305-
{
5306-
return existingCallsite;
5307-
}
5308-
}
5309-
5310-
return nullptr;
5311-
}
5312-
5256+
53135257
#if DBG_DUMP
53145258
const char16* JavascriptLibrary::GetStringTemplateCallsiteObjectKey(Var callsite)
53155259
{
@@ -5374,290 +5318,7 @@ namespace Js
53745318
}
53755319
#endif
53765320

5377-
bool StringTemplateCallsiteObjectComparer<ParseNodePtr>::Equals(ParseNodePtr x, RecyclerWeakReference<Js::RecyclableObject>* y)
5378-
{
5379-
Assert(x != nullptr);
5380-
Assert(x->nop == knopStrTemplate);
5381-
5382-
Js::RecyclableObject* obj = y->Get();
5383-
5384-
// If the weak reference is dead, we can't be equal.
5385-
if (obj == nullptr)
5386-
{
5387-
return false;
5388-
}
5389-
5390-
Js::ES5Array* callsite = Js::ES5Array::FromVar(obj);
5391-
uint32 length = callsite->GetLength();
5392-
Js::Var element;
5393-
Js::JavascriptString* str;
5394-
IdentPtr pid;
5395-
5396-
// If the length of string literals is different, these callsite objects are not equal.
5397-
if (x->AsParseNodeStrTemplate()->countStringLiterals != length)
5398-
{
5399-
return false;
5400-
}
5401-
5402-
JS_REENTRANCY_LOCK(reentrancyLock, callsite->GetScriptContext()->GetThreadContext());
5403-
Unused(reentrancyLock);
5404-
5405-
element = Js::JavascriptOperators::OP_GetProperty(callsite, Js::PropertyIds::raw, callsite->GetScriptContext());
5406-
Js::ES5Array* rawArray = Js::ES5Array::FromVar(element);
5407-
5408-
// Length of the raw strings should be the same as the cooked string literals.
5409-
AssertOrFailFast(length != 0 && length == rawArray->GetLength());
5410-
5411-
x = x->AsParseNodeStrTemplate()->pnodeStringRawLiterals;
5412-
5413-
for (uint32 i = 0; i < length - 1; i++)
5414-
{
5415-
BOOL hasElem = rawArray->DirectGetItemAt(i, &element);
5416-
AssertOrFailFast(hasElem);
5417-
str = Js::JavascriptString::FromVar(element);
5418-
5419-
Assert(x->nop == knopList);
5420-
Assert(x->AsParseNodeBin()->pnode1->nop == knopStr);
5421-
5422-
pid = x->AsParseNodeBin()->pnode1->AsParseNodeStr()->pid;
5423-
5424-
// If strings have different length, they aren't equal
5425-
if (pid->Cch() != str->GetLength())
5426-
{
5427-
return false;
5428-
}
5429-
5430-
// If the strings at this index are not equal, the callsite objects are not equal.
5431-
if (!JsUtil::CharacterBuffer<char16>::StaticEquals(pid->Psz(), str->GetString(), str->GetLength()))
5432-
{
5433-
return false;
5434-
}
5435-
5436-
x = x->AsParseNodeBin()->pnode2;
5437-
}
5438-
5439-
// There should be one more string in the callsite array - and the final string in the ParseNode
5440-
5441-
BOOL hasLastElem = rawArray->DirectGetItemAt(length - 1, &element);
5442-
AssertOrFailFast(hasLastElem);
5443-
str = Js::JavascriptString::FromVar(element);
5444-
5445-
Assert(x->nop == knopStr);
5446-
pid = x->AsParseNodeStr()->pid;
5447-
5448-
// If strings have different length, they aren't equal
5449-
if (pid->Cch() != str->GetLength())
5450-
{
5451-
return false;
5452-
}
5453-
5454-
// If the strings at this index are not equal, the callsite objects are not equal.
5455-
if (!JsUtil::CharacterBuffer<char16>::StaticEquals(pid->Psz(), str->GetString(), str->GetLength()))
5456-
{
5457-
return false;
5458-
}
5459-
5460-
return true;
5461-
}
5462-
5463-
bool StringTemplateCallsiteObjectComparer<ParseNodePtr>::Equals(ParseNodePtr x, ParseNodePtr y)
5464-
{
5465-
Assert(x != nullptr && y != nullptr);
5466-
Assert(x->nop == knopStrTemplate && y->nop == knopStrTemplate);
5467-
5468-
// If the ParseNode is the same, they are equal.
5469-
if (x == y)
5470-
{
5471-
return true;
5472-
}
5473-
5474-
x = x->AsParseNodeStrTemplate()->pnodeStringRawLiterals;
5475-
y = y->AsParseNodeStrTemplate()->pnodeStringRawLiterals;
5476-
5477-
// If one of the templates only includes one string value, the raw literals ParseNode will
5478-
// be a knopStr instead of knopList.
5479-
if (x->nop != y->nop)
5480-
{
5481-
return false;
5482-
}
5483-
5484-
const char16* pid_x;
5485-
const char16* pid_y;
5486-
5487-
while (x->nop == knopList)
5488-
{
5489-
// If y is knopStr here, that means x has more strings in the list than y does.
5490-
if (y->nop != knopList)
5491-
{
5492-
return false;
5493-
}
5494-
5495-
Assert(x->AsParseNodeBin()->pnode1->nop == knopStr);
5496-
Assert(y->AsParseNodeBin()->pnode1->nop == knopStr);
5497-
5498-
pid_x = x->AsParseNodeBin()->pnode1->AsParseNodeStr()->pid->Psz();
5499-
pid_y = y->AsParseNodeBin()->pnode1->AsParseNodeStr()->pid->Psz();
5500-
5501-
// If the pid values of each raw string don't match each other, these are different.
5502-
if (!DefaultComparer<const char16*>::Equals(pid_x, pid_y))
5503-
{
5504-
return false;
5505-
}
5506-
5507-
x = x->AsParseNodeBin()->pnode2;
5508-
y = y->AsParseNodeBin()->pnode2;
5509-
}
5510-
5511-
// If y is still knopList here, that means y has more strings in the list than x does.
5512-
if (y->nop != knopStr)
5513-
{
5514-
return false;
5515-
}
5516-
5517-
Assert(x->nop == knopStr);
5518-
5519-
pid_x = x->AsParseNodeStr()->pid->Psz();
5520-
pid_y = y->AsParseNodeStr()->pid->Psz();
5521-
5522-
// This is the final string in the raw literals list. Return true if they are equal.
5523-
return DefaultComparer<const char16*>::Equals(pid_x, pid_y);
5524-
}
5525-
5526-
hash_t StringTemplateCallsiteObjectComparer<ParseNodePtr>::GetHashCode(ParseNodePtr i)
5527-
{
5528-
hash_t hash = 0;
5529-
5530-
Assert(i != nullptr);
5531-
Assert(i->nop == knopStrTemplate);
5532-
5533-
i = i->AsParseNodeStrTemplate()->pnodeStringRawLiterals;
5534-
5535-
const char16* pid;
5536-
5537-
while (i->nop == knopList)
5538-
{
5539-
Assert(i->AsParseNodeBin()->pnode1->nop == knopStr);
5540-
5541-
pid = i->AsParseNodeBin()->pnode1->AsParseNodeStr()->pid->Psz();
5542-
5543-
hash ^= DefaultComparer<const char16*>::GetHashCode(pid);
5544-
hash ^= DefaultComparer<const char16*>::GetHashCode(_u("${}"));
5545-
5546-
i = i->AsParseNodeBin()->pnode2;
5547-
}
5548-
5549-
Assert(i->nop == knopStr);
5550-
5551-
pid = i->AsParseNodeStr()->pid->Psz();
5552-
5553-
hash ^= DefaultComparer<const char16*>::GetHashCode(pid);
5554-
5555-
return hash;
5556-
}
5557-
5558-
bool StringTemplateCallsiteObjectComparer<RecyclerWeakReference<Js::RecyclableObject>*>::Equals(RecyclerWeakReference<Js::RecyclableObject>* x, ParseNodePtr y)
5559-
{
5560-
return StringTemplateCallsiteObjectComparer<ParseNodePtr>::Equals(y, x);
5561-
}
5562-
5563-
bool StringTemplateCallsiteObjectComparer<RecyclerWeakReference<Js::RecyclableObject>*>::Equals(RecyclerWeakReference<Js::RecyclableObject>* x, RecyclerWeakReference<Js::RecyclableObject>* y)
5564-
{
5565-
Js::RecyclableObject* objLeft = x->Get();
5566-
Js::RecyclableObject* objRight = y->Get();
5567-
5568-
// If either WeakReference is dead, we can't be equal to anything.
5569-
if (objLeft == nullptr || objRight == nullptr)
5570-
{
5571-
return false;
5572-
}
5573-
5574-
// If the Var pointers are the same, they are equal.
5575-
if (objLeft == objRight)
5576-
{
5577-
return true;
5578-
}
5579-
5580-
Js::ES5Array* arrayLeft = Js::ES5Array::FromVar(objLeft);
5581-
Js::ES5Array* arrayRight = Js::ES5Array::FromVar(objRight);
5582-
uint32 lengthLeft = arrayLeft->GetLength();
5583-
uint32 lengthRight = arrayRight->GetLength();
5584-
Js::Var varLeft;
5585-
Js::Var varRight;
5586-
5587-
// If the length of string literals is different, these callsite objects are not equal.
5588-
if (lengthLeft != lengthRight)
5589-
{
5590-
return false;
5591-
}
5592-
5593-
AssertOrFailFast(lengthLeft != 0 && lengthRight != 0);
5594-
5595-
JS_REENTRANCY_LOCK(reentrancyLock, arrayLeft->GetScriptContext()->GetThreadContext());
5596-
Unused(reentrancyLock);
5597-
5598-
// Change to the set of raw strings.
5599-
varLeft = Js::JavascriptOperators::OP_GetProperty(arrayLeft, Js::PropertyIds::raw, arrayLeft->GetScriptContext());
5600-
arrayLeft = Js::ES5Array::FromVar(varLeft);
5601-
5602-
varRight = Js::JavascriptOperators::OP_GetProperty(arrayRight, Js::PropertyIds::raw, arrayRight->GetScriptContext());
5603-
arrayRight = Js::ES5Array::FromVar(varRight);
5604-
5605-
// Length of the raw strings should be the same as the cooked string literals.
5606-
AssertOrFailFast(lengthLeft == arrayLeft->GetLength());
5607-
AssertOrFailFast(lengthRight == arrayRight->GetLength());
5608-
5609-
for (uint32 i = 0; i < lengthLeft; i++)
5610-
{
5611-
BOOL hasLeft = arrayLeft->DirectGetItemAt(i, &varLeft);
5612-
AssertOrFailFast(hasLeft);
5613-
BOOL hasRight = arrayRight->DirectGetItemAt(i, &varRight);
5614-
AssertOrFailFast(hasRight);
5615-
5616-
// If the strings at this index are not equal, the callsite objects are not equal.
5617-
if (!Js::JavascriptString::Equals(JavascriptString::FromVar(varLeft), JavascriptString::FromVar(varRight)))
5618-
{
5619-
return false;
5620-
}
5621-
}
5622-
5623-
return true;
5624-
}
5625-
5626-
hash_t StringTemplateCallsiteObjectComparer<RecyclerWeakReference<Js::RecyclableObject>*>::GetHashCode(RecyclerWeakReference<Js::RecyclableObject>* o)
5627-
{
5628-
hash_t hash = 0;
5629-
5630-
Js::RecyclableObject* obj = o->Get();
5631-
5632-
if (obj == nullptr)
5633-
{
5634-
return hash;
5635-
}
5636-
JS_REENTRANCY_LOCK(reentrancyLock, obj->GetScriptContext()->GetThreadContext());
5637-
Unused(reentrancyLock);
5638-
5639-
Js::ES5Array* callsite = Js::ES5Array::FromVar(obj);
5640-
Js::Var var = Js::JavascriptOperators::OP_GetProperty(callsite, Js::PropertyIds::raw, callsite->GetScriptContext());
5641-
Js::ES5Array* rawArray = Js::ES5Array::FromVar(var);
5642-
5643-
AssertOrFailFast(rawArray->GetLength() > 0);
5644-
5645-
rawArray->DirectGetItemAt(0, &var);
5646-
Js::JavascriptString* str = Js::JavascriptString::FromVar(var);
5647-
hash ^= DefaultComparer<const char16*>::GetHashCode(str->GetSz());
5648-
5649-
for (uint32 i = 1; i < rawArray->GetLength(); i++)
5650-
{
5651-
hash ^= DefaultComparer<const char16*>::GetHashCode(_u("${}"));
5652-
5653-
BOOL hasItem = rawArray->DirectGetItemAt(i, &var);
5654-
AssertOrFailFast(hasItem);
5655-
str = Js::JavascriptString::FromVar(var);
5656-
hash ^= DefaultComparer<const char16*>::GetHashCode(str->GetSz());
5657-
}
5658-
5659-
return hash;
5660-
}
5321+
56615322

56625323
DynamicType * JavascriptLibrary::GetObjectLiteralType(uint16 requestedInlineSlotCapacity)
56635324
{

‎lib/Runtime/Library/JavascriptLibrary.h

+1-43
Original file line numberDiff line numberDiff line change
@@ -158,35 +158,6 @@ namespace Js
158158
};
159159
#endif
160160

161-
template <typename T>
162-
struct StringTemplateCallsiteObjectComparer
163-
{
164-
static bool Equals(T x, T y)
165-
{
166-
static_assert(false, "Unexpected type T");
167-
}
168-
static hash_t GetHashCode(T i)
169-
{
170-
static_assert(false, "Unexpected type T");
171-
}
172-
};
173-
174-
template <>
175-
struct StringTemplateCallsiteObjectComparer<ParseNodePtr>
176-
{
177-
static bool Equals(ParseNodePtr x, RecyclerWeakReference<Js::RecyclableObject>* y);
178-
static bool Equals(ParseNodePtr x, ParseNodePtr y);
179-
static hash_t GetHashCode(ParseNodePtr i);
180-
};
181-
182-
template <>
183-
struct StringTemplateCallsiteObjectComparer<RecyclerWeakReference<Js::RecyclableObject>*>
184-
{
185-
static bool Equals(RecyclerWeakReference<Js::RecyclableObject>* x, RecyclerWeakReference<Js::RecyclableObject>* y);
186-
static bool Equals(RecyclerWeakReference<Js::RecyclableObject>* x, ParseNodePtr y);
187-
static hash_t GetHashCode(RecyclerWeakReference<Js::RecyclableObject>* o);
188-
};
189-
190161
class JavascriptLibrary : public JavascriptLibraryBase
191162
{
192163
friend class EditAndContinue;
@@ -475,13 +446,6 @@ namespace Js
475446
Field(JsrtExternalTypesCache*) jsrtExternalTypesCache;
476447
Field(FunctionBody*) fakeGlobalFuncForUndefer;
477448

478-
typedef JsUtil::BaseHashSet<RecyclerWeakReference<RecyclableObject>*, Recycler, PowerOf2SizePolicy, RecyclerWeakReference<RecyclableObject>*, StringTemplateCallsiteObjectComparer> StringTemplateCallsiteObjectList;
479-
480-
// Used to store a list of template callsite objects.
481-
// We use the raw strings in the callsite object (or a string template parse node) to identify unique callsite objects in the list.
482-
// See abstract operation GetTemplateObject in ES6 Spec (RC1) 12.2.8.3
483-
Field(StringTemplateCallsiteObjectList*) stringTemplateCallsiteObjectList;
484-
485449
Field(ModuleRecordList*) moduleRecordList;
486450

487451
Field(OnlyWritablePropertyProtoChainCache) typesWithOnlyWritablePropertyProtoChain;
@@ -558,7 +522,6 @@ namespace Js
558522
cacheForCopyOnAccessArraySegments(nullptr),
559523
#endif
560524
referencedPropertyRecords(nullptr),
561-
stringTemplateCallsiteObjectList(nullptr),
562525
moduleRecordList(nullptr),
563526
rootPath(nullptr),
564527
bindRefChunkBegin(nullptr),
@@ -1061,12 +1024,7 @@ namespace Js
10611024
static bool IsCachedCopyOnAccessArrayCallSite(const JavascriptLibrary *lib, ArrayCallSiteInfo *arrayInfo);
10621025
template <typename T>
10631026
static void CheckAndConvertCopyOnAccessNativeIntArray(const T instance);
1064-
#endif
1065-
1066-
void EnsureStringTemplateCallsiteObjectList();
1067-
void AddStringTemplateCallsiteObject(RecyclableObject* callsite);
1068-
RecyclableObject* TryGetStringTemplateCallsiteObject(ParseNodePtr pnode);
1069-
RecyclableObject* TryGetStringTemplateCallsiteObject(RecyclableObject* callsite);
1027+
#endif
10701028

10711029
static void CheckAndInvalidateIsConcatSpreadableCache(PropertyId propertyId, ScriptContext *scriptContext);
10721030

‎test/es6/ES6StringTemplate.js

+47-64
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ var tests = [
127127
var callsite3 = GetCallsite`simple template literal 3`;
128128
var callsite4 = GetCallsite`simple template literal 3`;
129129

130-
assert.isTrue(callsite3 === callsite4, "different string template literals with the same string literal value create identical callsite objects");
130+
assert.isFalse(callsite3 === callsite4, "different string template literals (with the same string literal value) create different callsite objects");
131131

132132
var loopCallsite = undefined;
133133
for (var i = 0; i < 10; i++) {
@@ -349,65 +349,57 @@ var tests = [
349349
}
350350
},
351351
{
352-
name: "String template callsite objects are unique per-Realm and indexed by the raw strings",
352+
name: "Each string template literal corresponds to exactly one (cached) callsite object",
353353
body: function() {
354-
var callsite = undefined;
355-
var counter = 0;
356-
357-
function tag(c)
358-
{
359-
counter++;
360-
361-
assert.areEqual('uniquestringforrealmcachetest\\n', c.raw[0], 'String template callsite has correct raw value');
362-
363-
if (callsite === undefined) {
364-
callsite = c;
354+
var callsite1 = GetCallsite`simple template literal 1`;
355+
var callsite2 = GetCallsite`simple template literal 2`;
356+
357+
assert.isFalse(callsite1 === callsite2, "different string template literals create different callsite objects");
358+
359+
var callsite3 = GetCallsite`simple template literal 3`;
360+
var callsite4 = GetCallsite`simple template literal 3`;
361+
362+
assert.isFalse(callsite3 === callsite4, "different string template literals (with the same string literal value) create different callsite objects");
363+
364+
var loopCallsite = undefined;
365+
for (var i = 0; i < 10; i++) {
366+
var c = GetCallsite`loop template literal ${i}`;
367+
368+
if (loopCallsite === undefined) {
369+
loopCallsite = c;
365370
} else {
366-
assert.isTrue(c === callsite, 'Callsite is correctly cached per-Realm');
371+
assert.isTrue(loopCallsite === c, "string template literal used in a loop reuses the same callsite object.");
367372
}
373+
374+
assert.areEqual(2, c.length, "loop callsite has expected count of string literals");
375+
assert.areEqual("loop template literal ", c[0], "loop callsite has expected first string literal value");
376+
assert.areEqual("", c[1], "loop callsite has expected second string literal value");
377+
378+
assert.areEqual(2, c.raw.length, "loop callsite.raw has expected count of string literals");
379+
assert.areEqual("loop template literal ", c.raw[0], "loop callsite.raw has expected first string literal value");
380+
assert.areEqual("", c.raw[1], "loop callsite.raw has expected second string literal value");
368381
}
369-
370-
function foo() {
371-
tag`uniquestringforrealmcachetest\n`;
372-
tag`uniquestringforrealmcachetest\n`;
373-
}
374-
375-
foo();
376-
foo();
377-
378-
function foo2() {
379-
tag`uniquestringforrealmcachetest\n`;
380-
tag`uniquestringforrealmcachetest\n`;
381-
}
382-
383-
foo2();
384-
foo2();
385-
386-
function foo3() {
387-
eval('tag`uniquestringforrealmcachetest\\n`');
388-
eval('tag`uniquestringforrealmcachetest\\n`');
382+
383+
loopCallsite = undefined
384+
for (var i = 0; i < 10; i++) {
385+
var c = GetExpectedCachedCallsite();
386+
387+
if (loopCallsite === undefined) {
388+
loopCallsite = c;
389+
} else {
390+
assert.isTrue(loopCallsite === c, "string template declared in other function returns same callsite object when function called.");
391+
}
392+
393+
assert.areEqual(3, c.length, "loop callsite has expected count of string literals");
394+
assert.areEqual("some string template ", c[0], "loop callsite has expected first string literal value");
395+
assert.areEqual(" with replacements ", c[1], "loop callsite has expected second string literal value");
396+
assert.areEqual("", c[2], "loop callsite has expected third string literal value");
397+
398+
assert.areEqual(3, c.raw.length, "loop callsite.raw has expected count of string literals");
399+
assert.areEqual("some string template ", c.raw[0], "loop callsite.raw has expected first string literal value");
400+
assert.areEqual(" with replacements ", c.raw[1], "loop callsite.raw has expected second string literal value");
401+
assert.areEqual("", c.raw[2], "loop callsite.raw has expected third string literal value");
389402
}
390-
391-
foo3();
392-
foo3();
393-
394-
counter = 0;
395-
396-
var foo4 = new Function('t','t`uniquestringforrealmcachetest\\n`;');
397-
398-
foo4(tag);
399-
foo4(tag);
400-
401-
assert.areEqual(2, counter, "tag function is called correct number of times");
402-
403-
counter = 0;
404-
405-
var foo5 = new Function('t','eval("t`uniquestringforrealmcachetest\\\\n`;");');
406-
407-
foo5(tag);
408-
foo5(tag);
409-
410-
assert.areEqual(2, counter, "tag function is called correct number of times");
411403
}
412404
},
413405
{
@@ -426,15 +418,6 @@ after`;
426418
assert.isFalse(callsite1 === callsite2, 'Callsite objects are not the same ');
427419
}
428420
},
429-
{
430-
name: "Callsite objects are constant even if replacement values differ",
431-
body: function() {
432-
var callsite1 = GetCallsite`string1${'r1'}string2${'r2'}string3`;
433-
var callsite2 = GetCallsite`string1${'r3'}string2${'r4'}string3`;
434-
435-
assert.isTrue(callsite1 === callsite2, "Callsite objects are strictly equal");
436-
}
437-
},
438421
{
439422
name: "Octal escape sequences are not allowed in string template literals",
440423
body: function() {

0 commit comments

Comments
 (0)
Please sign in to comment.