⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 291756 in webkit


Ignore:
Timestamp:
Mar 23, 2022, 11:47:18 AM (5 years ago)
Author:
ysuzuki@apple.com
Message:

[JSC][MSVC] custom getter creation needs to include classInfo since MSVC ICF is not "safe" variant
​https://bugs.webkit.org/show_bug.cgi?id=238030

Reviewed by Alexey Shvayka.

MSVC performs very aggressive ICF (identical code folding) and it even merges the identical two functions
into one even though a pointer to this function is used. This means MSVC's ICF is not "safe"[1], and custom
function weakmap is broken on MSVC since it is assuming function pointers are different for different functions.
Unfortunately, it seems that there is no attribute / annotation to prevent this behavior, so we need to workaround it.
Since JSCustomGetterFunction does separate thing based on attached DOMAttribute, we need to include const ClassInfo*
into a key of JSCustomGetterFunction weakmap to ensure that two identical functions with different const ClassInfo*
do not get the same JSCustomGetterFunction.

[1]: ​https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/36912.pdf

  • runtime/JSCustomGetterFunction.h:
  • runtime/JSCustomSetterFunction.h:
  • runtime/JSGlobalObject.h:
  • runtime/JSGlobalObjectInlines.h:

(JSC::JSGlobalObject::WeakCustomGetterOrSetterHash<T>::hash):

  • runtime/JSObject.cpp:

(JSC::WeakCustomGetterOrSetterHashTranslator::hash):
(JSC::WeakCustomGetterOrSetterHashTranslator::equal):
(JSC::createCustomGetterFunction):
(JSC::createCustomSetterFunction):

Location:
trunk/Source/JavaScriptCore
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r291755 r291756  
     12022-03-23  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC][MSVC] custom getter creation needs to include classInfo since MSVC ICF is not "safe" variant
     4        https://bugs.webkit.org/show_bug.cgi?id=238030
     5
     6        Reviewed by Alexey Shvayka.
     7
     8        MSVC performs very aggressive ICF (identical code folding) and it even merges the identical two functions
     9        into one even though a pointer to this function is used. This means MSVC's ICF is not "safe"[1], and custom
     10        function weakmap is broken on MSVC since it is assuming function pointers are different for different functions.
     11        Unfortunately, it seems that there is no attribute / annotation to prevent this behavior, so we need to workaround it.
     12        Since JSCustomGetterFunction does separate thing based on attached DOMAttribute, we need to include const ClassInfo*
     13        into a key of JSCustomGetterFunction weakmap to ensure that two identical functions with different const ClassInfo*
     14        do not get the same JSCustomGetterFunction.
     15
     16        [1]: https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/36912.pdf
     17
     18        * runtime/JSCustomGetterFunction.h:
     19        * runtime/JSCustomSetterFunction.h:
     20        * runtime/JSGlobalObject.h:
     21        * runtime/JSGlobalObjectInlines.h:
     22        (JSC::JSGlobalObject::WeakCustomGetterOrSetterHash<T>::hash):
     23        * runtime/JSObject.cpp:
     24        (JSC::WeakCustomGetterOrSetterHashTranslator::hash):
     25        (JSC::WeakCustomGetterOrSetterHashTranslator::equal):
     26        (JSC::createCustomGetterFunction):
     27        (JSC::createCustomSetterFunction):
     28
    1292022-03-23  Chris Dumez  <cdumez@apple.com>
    230
  • trunk/Source/JavaScriptCore/runtime/JSCustomGetterFunction.h

    r290129 r291756  
    6060    CustomFunctionPointer customFunctionPointer() const { return m_getter; };
    6161    std::optional<DOMAttributeAnnotation> domAttribute() const { return m_domAttribute; };
     62    const ClassInfo* slotBaseClassInfoIfExists() const
     63    {
     64        if (m_domAttribute)
     65            return m_domAttribute->classInfo;
     66        return nullptr;
     67    }
    6268
    6369private:
  • trunk/Source/JavaScriptCore/runtime/JSCustomSetterFunction.h

    r290129 r291756  
    5959    CustomFunctionPointer setter() const { return m_setter; };
    6060    CustomFunctionPointer customFunctionPointer() const { return m_setter; };
     61    const ClassInfo* slotBaseClassInfoIfExists() const { return nullptr; }
    6162
    6263private:
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h

    r290209 r291756  
    600600        static unsigned hash(const Weak<T>&);
    601601        static bool equal(const Weak<T>&, const Weak<T>&);
    602         static unsigned hash(const PropertyName&, typename T::CustomFunctionPointer);
     602        static unsigned hash(const PropertyName&, typename T::CustomFunctionPointer, const ClassInfo*);
    603603
    604604        static constexpr bool safeToCompareToEmptyOrDeleted = false;
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h

    r284590 r291756  
    3535#include "LinkTimeConstant.h"
    3636#include "ObjectPrototype.h"
     37#include <wtf/Hasher.h>
    3738
    3839namespace JSC {
    … …  
    154155    if (!value)
    155156        return 0;
    156     return hash(value->propertyName(), value->customFunctionPointer());
     157    return hash(value->propertyName(), value->customFunctionPointer(), value->slotBaseClassInfoIfExists());
    157158}
    158159
    … …  
    166167
    167168template<typename T>
    168 inline unsigned JSGlobalObject::WeakCustomGetterOrSetterHash<T>::hash(const PropertyName& propertyName, typename T::CustomFunctionPointer functionPointer)
     169inline unsigned JSGlobalObject::WeakCustomGetterOrSetterHash<T>::hash(const PropertyName& propertyName, typename T::CustomFunctionPointer functionPointer, const ClassInfo* classInfo)
    169170{
    170     unsigned hash = DefaultHash<typename T::CustomFunctionPointer>::hash(functionPointer);
    171171    if (!propertyName.isNull())
    172         hash = WTF::pairIntHash(hash, propertyName.uid()->existingSymbolAwareHash());
    173     return hash;
     172        return WTF::computeHash(functionPointer, propertyName.uid()->existingSymbolAwareHash(), classInfo);
     173    return WTF::computeHash(functionPointer, classInfo);
    174174}
    175175
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r288815 r291756  
    36223622    using BaseHash = JSGlobalObject::WeakCustomGetterOrSetterHash<T>;
    36233623
    3624     using Key = std::pair<PropertyName, typename T::CustomFunctionPointer>;
     3624    using Key = std::tuple<PropertyName, typename T::CustomFunctionPointer, const ClassInfo*>;
    36253625
    36263626    static unsigned hash(const Key& key)
    36273627    {
    3628         return BaseHash::hash(std::get<0>(key), std::get<1>(key));
     3628        return BaseHash::hash(std::get<0>(key), std::get<1>(key), std::get<2>(key));
    36293629    }
    36303630
    … …  
    36333633        if (!a)
    36343634            return false;
    3635         return a->propertyName() == std::get<0>(b) && a->customFunctionPointer() == std::get<1>(b);
     3635        return a->propertyName() == std::get<0>(b) && a->customFunctionPointer() == std::get<1>(b) && a->slotBaseClassInfoIfExists() == std::get<2>(b);
    36363636    }
    36373637};
    … …  
    36443644    // We use DeferGC here (1) not to invoke GC when executing WeakGCSet::ensureValue and (2) to avoid looking up HashSet twice.
    36453645    DeferGC deferGC(vm);
    3646     return globalObject->customGetterFunctionSet().ensureValue<Translator>(std::make_pair(propertyName, getValueFunc), [&] {
     3646    const ClassInfo* classInfo = nullptr;
     3647    if (domAttribute)
     3648        classInfo = domAttribute->classInfo;
     3649    return globalObject->customGetterFunctionSet().ensureValue<Translator>(std::tuple { propertyName, getValueFunc, classInfo }, [&] {
    36473650        return JSCustomGetterFunction::create(vm, globalObject, propertyName, getValueFunc, domAttribute);
    36483651    });
    … …  
    36563659    // We use DeferGC here (1) not to invoke GC when executing WeakGCSet::ensureValue and (2) to avoid looking up HashSet twice.
    36573660    DeferGC deferGC(vm);
    3658     return globalObject->customSetterFunctionSet().ensureValue<Translator>(std::make_pair(propertyName, putValueFunc), [&] {
     3661    return globalObject->customSetterFunctionSet().ensureValue<Translator>(std::tuple { propertyName, putValueFunc, nullptr }, [&] {
    36593662        return JSCustomSetterFunction::create(vm, globalObject, propertyName, putValueFunc);
    36603663    });
Note: See TracChangeset for help on using the changeset viewer.