Skip to content

Commit 9fdb68b

Browse files
committed
OS#16526223: Keep writes to 'prototype' from going through inline cache so that we get the necessary runtime behavior
1 parent 5ec0ca7 commit 9fdb68b

File tree

6 files changed

+41
-0
lines changed

6 files changed

+41
-0
lines changed

lib/Runtime/Base/PropertyRecord.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ namespace Js
6868
}
6969
}
7070

71+
bool PropertyRecord::ShouldDisableWriteCache() const
72+
{
73+
// We can't cache stores to the 'prototype' property of function objects. We must go through the runtime and clear the constructor cache.
74+
// We could consider treating 'prototype' as an accessor on JavascriptFunction and friends, though this seems like it will grow the object.
75+
return pid == PropertyIds::prototype;
76+
}
77+
7178
#ifdef DEBUG
7279
// This is only used to assert that integer property names are not passed into
7380
// the GetSetter, GetProperty, SetProperty etc methods that take JavascriptString

lib/Runtime/Base/PropertyRecord.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ namespace Js
7777
bool IsBound() const { return isBound; }
7878
bool IsSymbol() const { return isSymbol; }
7979

80+
bool ShouldDisableWriteCache() const;
81+
8082
void SetHash(uint hash) const
8183
{
8284
this->hash = hash;

lib/Runtime/Library/PropertyRecordUsageCache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ namespace Js
3030
void RegisterCacheHit() { ++this->hitRate; };
3131
bool ShouldUseCache() const;
3232

33+
bool ShouldDisableWriteCache() const { return propertyRecord && propertyRecord->ShouldDisableWriteCache(); }
34+
3335
static uint32 GetOffsetOfLdElemInlineCache() { return offsetof(PropertyRecordUsageCache, ldElemInlineCache); }
3436
static uint32 GetOffsetOfStElemInlineCache() { return offsetof(PropertyRecordUsageCache, stElemInlineCache); }
3537
static uint32 GetOffsetOfHitRate() { return offsetof(PropertyRecordUsageCache, hitRate); }

lib/Runtime/Types/RecyclableObject.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ namespace Js
3939
info->prop = prop;
4040
info->propertyRecordUsageCache = propertyRecordUsageCache;
4141
SetCacheInfo(info, polymorphicInlineCache, allowResizing);
42+
if (propertyRecordUsageCache && propertyRecordUsageCache->ShouldDisableWriteCache())
43+
{
44+
info->ClearInfoFlag(CacheInfoFlag::enableStoreFieldCacheFlag);
45+
}
4246
}
4347

4448
void PropertyValueInfo::SetCacheInfo(_Out_ PropertyValueInfo* info, _In_ PolymorphicInlineCache *const polymorphicInlineCache, bool allowResizing)

test/Function/prototype_set.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
function f() {
7+
function inner() { }
8+
inner.__proto__ = {b:'b'}; // Put enumerable property into prototype chain
9+
new inner(); // Populate ctor cache
10+
for (var s in inner) { // Cache 'prototype' in TypePropertyCache while enumerating
11+
inner[s];
12+
}
13+
inner.prototype = {sox:'red'}; // Set new prototype, using inline cache on 2nd invocation
14+
return new inner(); // On 2nd invocation, try to construct using stale ctor cache
15+
}
16+
17+
f();
18+
var Boston = f();
19+
if (Boston.sox === 'red')
20+
WScript.Echo('pass');
21+

test/Function/rlexe.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@
226226
<baseline>prototype.baseline</baseline>
227227
</default>
228228
</test>
229+
<test>
230+
<default>
231+
<files>prototype_set.js</files>
232+
</default>
233+
</test>
229234
<test>
230235
<default>
231236
<files>TApply1.js</files>

0 commit comments

Comments
 (0)