Skip to content

Commit

Permalink
[JSC] AI should observe attribute change transitions for PutByIdDirec…
Browse files Browse the repository at this point in the history
…t in DFG compilation

https://bugs.webkit.org/show_bug.cgi?id=270265
rdar://122515736

Reviewed by Yusuke Suzuki.

Since DirectPutById can trigger and cache attribute change transitions,
the AI should observe these kinds of transitions when computing for
GetByStatus in the DFG compilation.

* JSTests/stress/dfg-ai-attribute-change-transition-1.js: Added.
(returnObject):
(Opt):
(createObjectA):
(createObjectB):
(initialize):
* JSTests/stress/dfg-ai-attribute-change-transition-2.js: Added.
(returnObject):
(Opt):
(createObject):
(getStructureID):
(main):
* Source/JavaScriptCore/bytecode/PutByStatus.cpp:
(JSC::PutByStatus::computeFor):
* Source/JavaScriptCore/runtime/Structure.cpp:
(JSC::Structure::attributeChangeTransitionToExistingStructureImpl):
(JSC::Structure::attributeChangeTransitionToExistingStructure):
(JSC::Structure::attributeChangeTransitionToExistingStructureConcurrently):
* Source/JavaScriptCore/runtime/Structure.h:

Originally-landed-as: 272448.651@safari-7618-branch (4e48bda). rdar://128090341
Canonical link: https://commits.webkit.org/278870@main
  • Loading branch information
hyjorc1 authored and robert-jenner committed May 16, 2024
1 parent ae8102d commit 332ec81
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
function returnObject(object) {
return object;
}

class Opt extends returnObject {
p2 = 1;

constructor(object) {
object.p1;

super(object);
}
}

function createObject() {
const object = {p1: 1};
Object.defineProperty(object, 'p2', {
configurable: true,
enumerable: false,
writable: true,
value: 1
});

return object;
}

function getStructureID(object) {
const desc = describe(object);

return desc.match(/StructureID: (\d+)/)[1];
}

function main() {
const a = createObject();
new Opt(a);

for (let i = 0; i < 100000; i++) {
new Opt(createObject());
}

const b = createObject();
new Opt(b);

const aStructureID = getStructureID(a);
const bStructureID = getStructureID(b);

if (aStructureID !== bStructureID)
throw new Error('Structure ID mismatch.');
}

main();
12 changes: 11 additions & 1 deletion Source/JavaScriptCore/bytecode/PutByStatus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,17 @@ PutByStatus PutByStatus::computeFor(JSGlobalObject* globalObject, const Structur

if (attributes & (PropertyAttribute::Accessor | PropertyAttribute::ReadOnly))
return PutByStatus(LikelyTakesSlowPath);


if (isDirect && attributes) {
Structure* existingTransition = Structure::attributeChangeTransitionToExistingStructureConcurrently(structure, identifier.uid(), 0, offset);
if (!existingTransition)
return PutByStatus(LikelyTakesSlowPath);
bool didAppend = result.appendVariant(PutByVariant::transition(identifier, structure, existingTransition, { }, offset));
if (!didAppend)
return PutByStatus(LikelyTakesSlowPath);
continue;
}

WatchpointSet* replaceSet = structure->propertyReplacementWatchpointSet(offset);
if (!replaceSet || replaceSet->isStillValid()) {
// When this executes, it'll create, and fire, this replacement watchpoint set.
Expand Down
14 changes: 13 additions & 1 deletion Source/JavaScriptCore/runtime/Structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ Structure* Structure::changePrototypeTransition(VM& vm, Structure* structure, JS
return transition;
}

Structure* Structure::attributeChangeTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset)
Structure* Structure::attributeChangeTransitionToExistingStructureImpl(Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset)
{
ASSERT(structure->isObject());

Expand All @@ -702,6 +702,18 @@ Structure* Structure::attributeChangeTransitionToExistingStructure(Structure* st
return nullptr;
}

Structure* Structure::attributeChangeTransitionToExistingStructure(Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset)
{
ASSERT(!isCompilationThread());
return attributeChangeTransitionToExistingStructureImpl(structure, propertyName, attributes, offset);
}

Structure* Structure::attributeChangeTransitionToExistingStructureConcurrently(Structure* structure, PropertyName propertyName, unsigned attributes, PropertyOffset& offset)
{
ConcurrentJSLocker locker(structure->m_lock);
return attributeChangeTransitionToExistingStructureImpl(structure, propertyName, attributes, offset);
}

Structure* Structure::attributeChangeTransition(VM& vm, Structure* structure, PropertyName propertyName, unsigned attributes, DeferredStructureTransitionWatchpointFire* deferred)
{
if (structure->isUncacheableDictionary()) {
Expand Down
4 changes: 3 additions & 1 deletion Source/JavaScriptCore/runtime/Structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ class Structure : public JSCell {
static Structure* removePropertyTransitionFromExistingStructureConcurrently(Structure*, PropertyName, PropertyOffset&);
static Structure* changePrototypeTransition(VM&, Structure*, JSValue prototype, DeferredStructureTransitionWatchpointFire&);
JS_EXPORT_PRIVATE static Structure* attributeChangeTransition(VM&, Structure*, PropertyName, unsigned attributes, DeferredStructureTransitionWatchpointFire* = nullptr);
static Structure* attributeChangeTransitionToExistingStructureConcurrently(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
JS_EXPORT_PRIVATE static Structure* attributeChangeTransitionToExistingStructure(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
JS_EXPORT_PRIVATE static Structure* toCacheableDictionaryTransition(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
static Structure* toUncacheableDictionaryTransition(VM&, Structure*, DeferredStructureTransitionWatchpointFire* = nullptr);
Expand Down Expand Up @@ -938,8 +939,9 @@ class Structure : public JSCell {
Structure(VM&, CreatingEarlyCellTag);

static Structure* create(VM&, Structure*, DeferredStructureTransitionWatchpointFire*);

static Structure* addPropertyTransitionToExistingStructureImpl(Structure*, UniquedStringImpl* uid, unsigned attributes, PropertyOffset&);
ALWAYS_INLINE static Structure* attributeChangeTransitionToExistingStructureImpl(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
static Structure* removePropertyTransitionFromExistingStructureImpl(Structure*, PropertyName, unsigned attributes, PropertyOffset&);
static Structure* setBrandTransitionFromExistingStructureImpl(Structure*, UniquedStringImpl*);

Expand Down

0 comments on commit 332ec81

Please sign in to comment.