Skip to content

Commit

Permalink
Cherry-pick 4e48bda. rdar://123858251
Browse files Browse the repository at this point in the history
    [JSC] AI should observe attribute change transitions for PutByIdDirect 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:

    Canonical link: https://commits.webkit.org/272448.651@safari-7618-branch
  • Loading branch information
hyjorc1 authored and Mohsin Qureshi committed Mar 7, 2024
1 parent d0d9055 commit 1bb7279
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 @@ -403,7 +403,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 @@ -677,7 +677,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 @@ -695,6 +695,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 1bb7279

Please sign in to comment.