Skip to content
Open
Show file tree
Hide file tree
Changes from 6 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
9 changes: 9 additions & 0 deletions lib/Runtime/Base/ThreadContext.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
Expand Down Expand Up @@ -1384,6 +1385,14 @@ class ThreadContext sealed :
#endif

public:
template<class Fn>
void MapIsInstInlineCaches(Fn fn) const
{
isInstInlineCacheByFunction.Map([fn](const Js::Var function, Js::IsInstInlineCache* inlineCacheList) {
fn(function, inlineCacheList);
});
}

void InvalidateIsInstInlineCachesForFunction(Js::Var function);
void InvalidateAllIsInstInlineCaches();
bool AreAllIsInstInlineCachesInvalidated() const;
Expand Down
35 changes: 34 additions & 1 deletion lib/Runtime/Library/JavascriptObject.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeLibraryPch.h"
Expand Down Expand Up @@ -247,6 +247,39 @@ BOOL JavascriptObject::ChangePrototype(RecyclableObject* object, RecyclableObjec

if (isInvalidationOfInlineCacheNeeded)
{
// Invalidate the "instanceof" cache
ThreadContext* threadContext = scriptContext->GetThreadContext();
threadContext->MapIsInstInlineCaches([threadContext, object](const Js::Var function, Js::IsInstInlineCache* inlineCacheList) {
Assert(inlineCacheList != nullptr);

Js::IsInstInlineCache* curInlineCache;
Js::IsInstInlineCache* nextInlineCache;
for (curInlineCache = inlineCacheList; curInlineCache != nullptr; curInlineCache = nextInlineCache)
{
// Stash away the next cache before we potentially zero out current one
nextInlineCache = curInlineCache->next;

bool clearCurrentCache = curInlineCache->type == object->GetType();
if (!clearCurrentCache) {
// Check if function prototype contains old prototype
JavascriptOperators::MapObjectAndPrototypes<true>(curInlineCache->type->GetPrototype(), [&](RecyclableObject* obj)
{
if (object->GetType() == obj->GetType())
clearCurrentCache = true;
});
}

if (clearCurrentCache)
{
// Fix cache list
// Deletes empty entries
threadContext->UnregisterIsInstInlineCache(curInlineCache, function);
// Actually invalidate current cache
memset(curInlineCache, 0, sizeof(Js::IsInstInlineCache));
}
}
});

bool allProtoCachesInvalidated = false;

JavascriptOperators::MapObjectAndPrototypes<true>(newPrototype, [&](RecyclableObject* obj)
Expand Down
37 changes: 37 additions & 0 deletions test/InlineCaches/isinstanceof.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Copyright (c) ChakraCore Project Contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------

// @ts-check
/// <reference path="..\UnitTestFramework\UnitTestFramework.js" />
WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");

const tests = [{
name: "Clear IsInstInlineCache of 'Object.setPrototypeOf'",
body: function () {
// See https://github.com/chakra-core/ChakraCore/issues/5915

function Component() { }
function Shape() { }

function Box() { }
Box.prototype = Object.create(Shape.prototype);
Box.prototype.constructor = Box;

function checkInstanceOf(a, b) {
return a instanceof b;
}

assert.isFalse(Box.prototype instanceof Component, "Box.prototype instanceof Component");
assert.isFalse(checkInstanceOf(Box.prototype, Component), "checkInstanceOf(Box.prototype, Component)");

Object.setPrototypeOf(Shape.prototype, Component.prototype);

assert.isTrue(Box.prototype instanceof Component, "Box.prototype instanceof Component");
assert.isTrue(checkInstanceOf(Box.prototype, Component), "checkInstanceOf(Box.prototype, Component)");
}
}];

testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
6 changes: 6 additions & 0 deletions test/InlineCaches/rlexe.xml
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,10 @@
<baseline>bug_vso_os_1206083.baseline</baseline>
</default>
</test>
<test>
<default>
<files>isinstanceof.js</files>
<compile-flags>-args summary -endargs</compile-flags>
</default>
</test>
</regress-exe>