Skip to content

Commit

Permalink
[JSC] setHasModifiedLengthForBoundOrNonHostFunction and setHasModifie…
Browse files Browse the repository at this point in the history
…dNameForBoundOrNonHostFunction shouldn't be called if it fails to reify the property

https://bugs.webkit.org/show_bug.cgi?id=267380
rdar://118761737

Reviewed by Yusuke Suzuki.

setHasModifiedLengthForBoundOrNonHostFunction and setHasModifiedNameForBoundOrNonHostFunction
can be called if JSFunction::put() fails to reify the property. This case may
cause inconsistency between the AI and the runtime environment.

* Source/JavaScriptCore/runtime/JSFunction.cpp:
(JSC::JSFunction::put):

Originally-landed-as: 272448.101@safari-7618-branch (70ca9c1). rdar://124556382
Canonical link: https://commits.webkit.org/276106@main
  • Loading branch information
hyjorc1 authored and robert-jenner committed Mar 14, 2024
1 parent ffe58e2 commit 4e7c454
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 50 deletions.
4 changes: 2 additions & 2 deletions Source/JavaScriptCore/runtime/CommonSlowPaths.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ static ALWAYS_INLINE void putDirectWithReify(VM& vm, JSGlobalObject* globalObjec
auto scope = DECLARE_THROW_SCOPE(vm);
bool isJSFunction = baseObject->inherits<JSFunction>();
if (isJSFunction) {
jsCast<JSFunction*>(baseObject)->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
jsCast<JSFunction*>(baseObject)->reifyLazyPropertyIfNeeded<>(vm, globalObject, propertyName);
RETURN_IF_EXCEPTION(scope, void());
}

Expand All @@ -204,7 +204,7 @@ static ALWAYS_INLINE void putDirectAccessorWithReify(VM& vm, JSGlobalObject* glo
auto scope = DECLARE_THROW_SCOPE(vm);
bool isJSFunction = baseObject->inherits<JSFunction>();
if (isJSFunction) {
jsCast<JSFunction*>(baseObject)->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
jsCast<JSFunction*>(baseObject)->reifyLazyPropertyIfNeeded<>(vm, globalObject, propertyName);
RETURN_IF_EXCEPTION(scope, void());
}

Expand Down
2 changes: 1 addition & 1 deletion Source/JavaScriptCore/runtime/IntlCollatorPrototype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ JSC_DEFINE_CUSTOM_GETTER(intlCollatorPrototypeGetterCompare, (JSGlobalObject* gl
// c. Let bc be BoundFunctionCreate(F, «this value»).
boundCompare = JSBoundFunction::create(vm, globalObject, targetObject, collator, { }, 2, jsEmptyString(vm));
RETURN_IF_EXCEPTION(scope, { });
boundCompare->reifyLazyPropertyIfNeeded(vm, globalObject, vm.propertyNames->name);
boundCompare->reifyLazyPropertyIfNeeded<>(vm, globalObject, vm.propertyNames->name);
RETURN_IF_EXCEPTION(scope, { });
boundCompare->putDirect(vm, vm.propertyNames->name, jsEmptyString(vm), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
// d. Set collator.[[boundCompare]] to bc.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ JSC_DEFINE_CUSTOM_GETTER(intlDateTimeFormatPrototypeGetterFormat, (JSGlobalObjec
// c. Let bf be BoundFunctionCreate(F, «this value»).
boundFormat = JSBoundFunction::create(vm, globalObject, targetObject, dtf, { }, 1, jsEmptyString(vm));
RETURN_IF_EXCEPTION(scope, { });
boundFormat->reifyLazyPropertyIfNeeded(vm, globalObject, vm.propertyNames->name);
boundFormat->reifyLazyPropertyIfNeeded<>(vm, globalObject, vm.propertyNames->name);
RETURN_IF_EXCEPTION(scope, { });
boundFormat->putDirect(vm, vm.propertyNames->name, jsEmptyString(vm), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
// d. Set dtf.[[boundFormat]] to bf.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ JSC_DEFINE_CUSTOM_GETTER(intlNumberFormatPrototypeGetterFormat, (JSGlobalObject*
// c. Let bf be BoundFunctionCreate(F, «this value»).
boundFormat = JSBoundFunction::create(vm, globalObject, targetObject, nf, { }, 1, jsEmptyString(vm));
RETURN_IF_EXCEPTION(scope, { });
boundFormat->reifyLazyPropertyIfNeeded(vm, globalObject, vm.propertyNames->name);
boundFormat->reifyLazyPropertyIfNeeded<>(vm, globalObject, vm.propertyNames->name);
RETURN_IF_EXCEPTION(scope, { });
boundFormat->putDirect(vm, vm.propertyNames->name, jsEmptyString(vm), PropertyAttribute::ReadOnly | PropertyAttribute::DontEnum);
// d. Set nf.[[boundFormat]] to bf.
Expand Down
70 changes: 31 additions & 39 deletions Source/JavaScriptCore/runtime/JSFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ bool JSFunction::getOwnPropertySlot(JSObject* object, JSGlobalObject* globalObje
return true;
}

thisObject->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
thisObject->reifyLazyPropertyIfNeeded<JSFunction::SetHasModifiedLengthOrName::No>(vm, globalObject, propertyName);
RETURN_IF_EXCEPTION(scope, false);

RELEASE_AND_RETURN(scope, Base::getOwnPropertySlot(thisObject, globalObject, propertyName, slot));
Expand Down Expand Up @@ -389,14 +389,6 @@ bool JSFunction::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName pr

JSFunction* thisObject = jsCast<JSFunction*>(cell);

if (propertyName == vm.propertyNames->length || propertyName == vm.propertyNames->name) {
FunctionRareData* rareData = thisObject->ensureRareData(vm);
if (propertyName == vm.propertyNames->length)
rareData->setHasModifiedLengthForBoundOrNonHostFunction();
else
rareData->setHasModifiedNameForBoundOrNonHostFunction();
}

if (propertyName == vm.propertyNames->prototype && thisObject->mayHaveNonReifiedPrototype()) {
slot.disableCaching();
if (FunctionRareData* rareData = thisObject->rareData())
Expand All @@ -412,7 +404,7 @@ bool JSFunction::put(JSCell* cell, JSGlobalObject* globalObject, PropertyName pr
RELEASE_AND_RETURN(scope, Base::put(thisObject, globalObject, propertyName, value, slot));
}

PropertyStatus propertyType = thisObject->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
PropertyStatus propertyType = thisObject->reifyLazyPropertyIfNeeded<>(vm, globalObject, propertyName);
RETURN_IF_EXCEPTION(scope, false);
if (isLazy(propertyType))
slot.disableCaching();
Expand All @@ -425,15 +417,7 @@ bool JSFunction::deleteProperty(JSCell* cell, JSGlobalObject* globalObject, Prop
auto scope = DECLARE_THROW_SCOPE(vm);
JSFunction* thisObject = jsCast<JSFunction*>(cell);

if (propertyName == vm.propertyNames->length || propertyName == vm.propertyNames->name) {
FunctionRareData* rareData = thisObject->ensureRareData(vm);
if (propertyName == vm.propertyNames->length)
rareData->setHasModifiedLengthForBoundOrNonHostFunction();
else
rareData->setHasModifiedNameForBoundOrNonHostFunction();
}

thisObject->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
thisObject->reifyLazyPropertyIfNeeded<>(vm, globalObject, propertyName);
RETURN_IF_EXCEPTION(scope, false);

RELEASE_AND_RETURN(scope, Base::deleteProperty(thisObject, globalObject, propertyName, slot));
Expand All @@ -446,13 +430,6 @@ bool JSFunction::defineOwnProperty(JSObject* object, JSGlobalObject* globalObjec

JSFunction* thisObject = jsCast<JSFunction*>(object);

if (propertyName == vm.propertyNames->length || propertyName == vm.propertyNames->name) {
FunctionRareData* rareData = thisObject->ensureRareData(vm);
if (propertyName == vm.propertyNames->length)
rareData->setHasModifiedLengthForBoundOrNonHostFunction();
else
rareData->setHasModifiedNameForBoundOrNonHostFunction();
}

if (propertyName == vm.propertyNames->prototype && thisObject->mayHaveNonReifiedPrototype()) {
if (FunctionRareData* rareData = thisObject->rareData())
Expand All @@ -467,7 +444,7 @@ bool JSFunction::defineOwnProperty(JSObject* object, JSGlobalObject* globalObjec
thisObject->putDirect(vm, propertyName, constructPrototypeObject(globalObject, thisObject), prototypeAttributesForNonClass);
}
} else {
thisObject->reifyLazyPropertyIfNeeded(vm, globalObject, propertyName);
thisObject->reifyLazyPropertyIfNeeded<>(vm, globalObject, propertyName);
RETURN_IF_EXCEPTION(scope, false);
}

Expand Down Expand Up @@ -610,21 +587,36 @@ JSFunction::PropertyStatus JSFunction::reifyName(VM& vm, JSGlobalObject* globalO
return PropertyStatus::Reified;
}

template <JSFunction::SetHasModifiedLengthOrName set>
JSFunction::PropertyStatus JSFunction::reifyLazyPropertyIfNeeded(VM& vm, JSGlobalObject* globalObject, PropertyName propertyName)
{
JSFunction::PropertyStatus status;
if (isHostOrBuiltinFunction())
return reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, globalObject, propertyName);

PropertyStatus lazyPrototype = reifyLazyPrototypeIfNeeded(vm, globalObject, propertyName);
if (isLazy(lazyPrototype))
return lazyPrototype;
PropertyStatus lazyLength = reifyLazyLengthIfNeeded(vm, globalObject, propertyName);
if (isLazy(lazyLength))
return lazyLength;
PropertyStatus lazyName = reifyLazyNameIfNeeded(vm, globalObject, propertyName);
if (isLazy(lazyName))
return lazyName;
return PropertyStatus::Eager;
status = reifyLazyPropertyForHostOrBuiltinIfNeeded(vm, globalObject, propertyName);
else if (PropertyStatus lazyPrototype = reifyLazyPrototypeIfNeeded(vm, globalObject, propertyName); isLazy(lazyPrototype))
status = lazyPrototype;
else if (PropertyStatus lazyLength = reifyLazyLengthIfNeeded(vm, globalObject, propertyName); isLazy(lazyLength))
status = lazyLength;
else if (PropertyStatus lazyName = reifyLazyNameIfNeeded(vm, globalObject, propertyName); isLazy(lazyName))
status = lazyName;
else
status = PropertyStatus::Eager;

if constexpr (set == SetHasModifiedLengthOrName::Yes) {
if (isNonBoundHostFunction() || !structure()->didTransition())
return status;
bool isLengthProperty = propertyName == vm.propertyNames->length;
bool isNameProperty = propertyName == vm.propertyNames->name;
if (!isLengthProperty && !isNameProperty)
return status;
FunctionRareData* rareData = ensureRareData(vm);
if (isLengthProperty)
rareData->setHasModifiedLengthForBoundOrNonHostFunction();
else
rareData->setHasModifiedNameForBoundOrNonHostFunction();
}

return status;
}

JSFunction::PropertyStatus JSFunction::reifyLazyPropertyForHostOrBuiltinIfNeeded(VM& vm, JSGlobalObject* globalObject, PropertyName propertyName)
Expand Down
3 changes: 3 additions & 0 deletions Source/JavaScriptCore/runtime/JSFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class JSFunction : public JSCallee {

// To call any of these methods include JSFunctionInlines.h
bool isHostFunction() const;
bool isNonBoundHostFunction() const;
FunctionExecutable* jsExecutable() const;
Intrinsic intrinsic() const;

Expand Down Expand Up @@ -163,6 +164,8 @@ class JSFunction : public JSCallee {
Lazy,
Reified,
};
enum class SetHasModifiedLengthOrName : uint8_t { Yes, No };
template <SetHasModifiedLengthOrName set = SetHasModifiedLengthOrName::Yes>
PropertyStatus reifyLazyPropertyIfNeeded(VM&, JSGlobalObject*, PropertyName);

bool canAssumeNameAndLengthAreOriginal(VM&);
Expand Down
15 changes: 9 additions & 6 deletions Source/JavaScriptCore/runtime/JSFunctionInlines.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ inline bool JSFunction::isHostFunction() const
return executable()->isHostFunction();
}

inline bool JSFunction::isNonBoundHostFunction() const
{
return isHostFunction() && !inherits<JSBoundFunction>();
}

inline Intrinsic JSFunction::intrinsic() const
{
return executable()->intrinsic();
Expand Down Expand Up @@ -203,12 +208,10 @@ inline JSString* JSFunction::originalName(JSGlobalObject* globalObject)

inline bool JSFunction::canAssumeNameAndLengthAreOriginal(VM&)
{
if (isHostFunction()) {
// Bound functions are not eagerly generating name and length.
// Thus, we can use FunctionRareData's tracking. This is useful to optimize func.bind().bind() case.
if (!inherits<JSBoundFunction>())
return false;
}
// Bound functions are not eagerly generating name and length.
// Thus, we can use FunctionRareData's tracking. This is useful to optimize func.bind().bind() case.
if (isNonBoundHostFunction())
return false;
FunctionRareData* rareData = this->rareData();
if (!rareData)
return true;
Expand Down

0 comments on commit 4e7c454

Please sign in to comment.