-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Changing a JSFunction's prototype property should clear allocation ca…
…ches https://bugs.webkit.org/show_bug.cgi?id=270302 rdar://121657868 Reviewed by Alexey Shvayka and Yusuke Suzuki. Right now we only clear the allocation watchpoint if a JSFunction `mayHaveNonReifiedPrototype()` when setting the .prototype property. This is semantically incorrect in the case of `new.target` bound functions because we will cache the wrong value. This patch makes it so we always file the allocation profile watchpoint when turning either of the allocation profiles. When turning the ObjectAllocationProfile (used by op_create_this) we assert the watchpoint has already been fired as it should've already happened when the new .prototype value was set. When turning the InternalFunctionAllocationProfile (used by createSubclassStructure when subclassing InternalFunction/Reflect.construct) its possible to pass the same JSFunction to two different InternalFunctions, which will turn the profile. * JSTests/stress/bound-constructor-change-prototype-clears-cache.js: Added. (empty): (test1.const.newTarget): (test1): (test2.const.newTarget): (test2.Opt): (test2): (test3.const.newTarget): (main): * JSTests/stress/put-prototype-to-normal-function-shouldnt-be-cached.js: Added. (opt): (main.target): (main): * Source/JavaScriptCore/bytecode/InternalFunctionAllocationProfile.h: (JSC::InternalFunctionAllocationProfile::createAllocationStructureFromBase): * Source/JavaScriptCore/bytecode/ObjectAllocationProfileInlines.h: (JSC::ObjectAllocationProfileBase<Derived>::initializeProfile): * Source/JavaScriptCore/dfg/DFGOperations.cpp: (JSC::DFG::JSC_DEFINE_JIT_OPERATION): * Source/JavaScriptCore/runtime/CommonSlowPaths.cpp: (JSC::JSC_DEFINE_COMMON_SLOW_PATH): (JSC::createInternalFieldObject): * Source/JavaScriptCore/runtime/FunctionRareData.h: * Source/JavaScriptCore/runtime/InternalFunction.cpp: (JSC::InternalFunction::createSubclassStructure): * Source/JavaScriptCore/runtime/JSFunction.cpp: (JSC::JSFunction::prototypeForConstruction): (JSC::JSFunction::allocateAndInitializeRareData): (JSC::JSFunction::initializeRareData): (JSC::JSFunction::put): (JSC::JSFunction::defineOwnProperty): * Source/JavaScriptCore/runtime/JSFunction.h: * Source/JavaScriptCore/runtime/JSFunctionInlines.h: (JSC::JSFunction::canUseAllocationProfiles): (JSC::JSFunction::ensureRareDataAndObjectAllocationProfile): (JSC::JSFunction::canUseAllocationProfile): Deleted. (JSC::JSFunction::ensureRareDataAndAllocationProfile): Deleted. Originally-landed-as: 272448.699@safari-7618-branch (96283e8). rdar://128089585 Canonical link: https://commits.webkit.org/278869@main
- Loading branch information
1 parent
31319e7
commit ae8102d
Showing
11 changed files
with
183 additions
and
62 deletions.
There are no files selected for viewing
73 changes: 73 additions & 0 deletions
73
JSTests/stress/bound-constructor-change-prototype-clears-cache.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
function empty() { | ||
|
||
} | ||
|
||
function test1() { | ||
const newTarget = (function () {}).bind(); | ||
newTarget.prototype = Object.prototype; | ||
|
||
const a = Reflect.construct(Promise, [empty], newTarget); | ||
|
||
newTarget.prototype = Array.prototype; | ||
|
||
const b = Reflect.construct(Promise, [empty], newTarget); | ||
|
||
if (a.__proto__ === b.__proto__) | ||
throw new Error('They should be different.'); | ||
} | ||
|
||
function test2() { | ||
const newTarget = (function () {}).bind(); | ||
newTarget.prototype = Object.prototype; | ||
|
||
const newTargetWrapper = Function.prototype.apply; | ||
newTargetWrapper.prototype = newTarget; | ||
|
||
class Opt extends Promise { | ||
constructor() { | ||
newTargetWrapper.prototype = new.target; | ||
empty instanceof newTargetWrapper; | ||
|
||
super(empty); | ||
} | ||
} | ||
|
||
for (let i = 0; i < 200000; i++) { | ||
Reflect.construct(Opt, [], newTarget); | ||
} | ||
|
||
const a = Reflect.construct(Opt, [], newTarget); | ||
|
||
newTarget.prototype = Array.prototype; | ||
Reflect.construct(Object, [], newTarget); | ||
|
||
const b = Reflect.construct(Opt, [], newTarget); | ||
|
||
if (a.__proto__ === b.__proto__) | ||
throw new Error('They should be different.'); | ||
} | ||
|
||
function test3() { | ||
const newTarget = (function () {}).bind(); | ||
let prototype = Object.prototype; | ||
Object.defineProperty(newTarget, "prototype", { get() { return prototype; }}); | ||
|
||
const a = Reflect.construct(Promise, [empty], newTarget); | ||
|
||
prototype = Array.prototype; | ||
|
||
const b = Reflect.construct(Promise, [empty], newTarget); | ||
|
||
if (a.__proto__ == b.__proto__) | ||
throw new Error('They should be different.'); | ||
} | ||
|
||
function main() { | ||
test1(); | ||
|
||
test2(); | ||
|
||
test3(); | ||
} | ||
|
||
main(); |
38 changes: 38 additions & 0 deletions
38
JSTests/stress/put-prototype-to-normal-function-shouldnt-be-cached.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
function opt(object, value) { | ||
object.prototype = value; | ||
} | ||
|
||
function main() { | ||
Function.prototype.__proto__ = new Proxy({}, {}); | ||
|
||
const object = { | ||
nonConstructor() { } | ||
}; | ||
|
||
function target() { } | ||
|
||
Function.prototype.__proto__ = Object.prototype; | ||
|
||
const nonConstructor = object.nonConstructor; | ||
|
||
Object.defineProperty(nonConstructor, 'prototype', { | ||
configurable: false, | ||
enumerable: false, | ||
writable: true, | ||
value: {} | ||
}); | ||
|
||
target.prototype = {}; | ||
Reflect.construct(Object, [], target); | ||
|
||
opt(nonConstructor, {}); | ||
const newPrototype = {}; | ||
opt(target, newPrototype); | ||
|
||
const result = Reflect.construct(Object, [], target); | ||
|
||
if (result.__proto__ !== newPrototype) | ||
throw new Error("Rare data of result was not cleared."); | ||
} | ||
|
||
main(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.