Skip to content

Commit 34a9c0b

Browse files
committed
[1.4>master] [MERGE #2298 @ThomsonTan] Remove downward lookup when searching shadowed property in prototype chain in for...in
Merge pull request #2298 from ThomsonTan:FixShadowPropertyInForIn The previous fix of shadowing non-enumerable property for for...in (#2175) added downward lookup in prototype chain which could degrade performance in edge cases. This fix followed suggestion from Curtis and only ignores lookup in prototype chain if there is no enumerable properties in the whole chain, otherwise search from the first prototype. The perf data for which we optimized for in enumerator looks flat.
2 parents c40f086 + 6a8a129 commit 34a9c0b

File tree

2 files changed

+6
-35
lines changed

2 files changed

+6
-35
lines changed

lib/Runtime/Library/ForInObjectEnumerator.cpp

Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,11 @@ namespace Js
1111
ForInObjectEnumerator::ShadowData::ShadowData(
1212
RecyclableObject * initObject,
1313
RecyclableObject * firstPrototype,
14-
RecyclableObject * firstPrototypeWithEnumerableProperties,
1514
Recycler * recycler)
1615
: currentObject(initObject),
1716
firstPrototype(firstPrototype),
18-
firstPrototypeWithEnumerableProperties(firstPrototypeWithEnumerableProperties),
1917
propertyIds(recycler)
2018
{
21-
2219
}
2320

2421
ForInObjectEnumerator::ForInObjectEnumerator(RecyclableObject* object, ScriptContext * scriptContext, bool enumSymbols)
@@ -53,9 +50,10 @@ namespace Js
5350
if (firstPrototypeWithEnumerableProperties != nullptr)
5451
{
5552
Recycler *recycler = requestContext->GetRecycler();
56-
this->shadowData = RecyclerNew(recycler, ShadowData, initObject, firstPrototype, firstPrototypeWithEnumerableProperties, recycler);
53+
this->shadowData = RecyclerNew(recycler, ShadowData, initObject, firstPrototype, recycler);
5754
flags = EnumeratorFlags::UseCache | EnumeratorFlags::SnapShotSemantics | EnumeratorFlags::EnumNonEnumerable | (enumSymbols ? EnumeratorFlags::EnumSymbols : EnumeratorFlags::None);
5855
}
56+
// no enumerable properties in the prototype chain, no need to search it
5957
else
6058
{
6159
this->shadowData = nullptr;
@@ -203,36 +201,10 @@ namespace Js
203201
}
204202
}
205203

206-
//check for shadowed property
207204
if (TestAndSetEnumerated(propertyId) //checks if the property is already enumerated or not
208205
&& (attributes & PropertyEnumerable))
209206
{
210-
bool propertyShadowed = false;
211-
212-
if (this->enumeratingPrototype)
213-
{
214-
// prototype checking begins from the first prototype object with enumerable properties,
215-
// but the property could be shadowed by a desendant prototype which has the same property but not enumerable.
216-
// Need to check that because that is ignored from the begining.
217-
RecyclableObject * prototypeObject = this->shadowData->firstPrototype;
218-
219-
while (prototypeObject != nullptr && prototypeObject != this->shadowData->currentObject)
220-
{
221-
if (prototypeObject->HasProperty(propertyId))
222-
{
223-
propertyShadowed = true;
224-
break;
225-
}
226-
prototypeObject = prototypeObject->GetPrototype();
227-
228-
Assert(prototypeObject != nullptr);
229-
}
230-
}
231-
232-
if (!propertyShadowed)
233-
{
234-
return currentIndex;
235-
}
207+
return currentIndex;
236208
}
237209
}
238210
else
@@ -244,10 +216,10 @@ namespace Js
244216
}
245217

246218
RecyclableObject * object;
247-
if (!enumeratingPrototype)
219+
if (!this->enumeratingPrototype)
248220
{
249221
this->enumeratingPrototype = true;
250-
object = this->shadowData->firstPrototypeWithEnumerableProperties;
222+
object = this->shadowData->firstPrototype;
251223
this->shadowData->currentObject = object;
252224
}
253225
else

lib/Runtime/Library/ForInObjectEnumerator.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ namespace Js
1212
JavascriptStaticEnumerator enumerator;
1313
struct ShadowData
1414
{
15-
ShadowData(RecyclableObject * initObject, RecyclableObject * firstPrototype, RecyclableObject * firstPrototypeWithEnumerableProperties, Recycler * recycler);
15+
ShadowData(RecyclableObject * initObject, RecyclableObject * firstPrototype, Recycler * recycler);
1616
RecyclableObject * currentObject;
1717
RecyclableObject * firstPrototype;
18-
RecyclableObject * firstPrototypeWithEnumerableProperties;
1918
BVSparse<Recycler> propertyIds;
2019
SListBase<Js::PropertyRecord const *> newPropertyStrings;
2120
} *shadowData;

0 commit comments

Comments
 (0)