Changeset 276106 in webkit


Ignore:
Timestamp:
Apr 15, 2021 7:06:31 PM (3 years ago)
Author:
mark.lam@apple.com
Message:

HashMapImpl::rehash() should use a version of jsMapHash that cannot throw.
https://bugs.webkit.org/show_bug.cgi?id=224610
rdar://76698910

Reviewed by Yusuke Suzuki.

JSTests:

  • stress/suppress-TerminationException-in-HashMapImpl-rehash.js: Added.

Source/JavaScriptCore:

For context, HashMapImpl::rehash()'s rehash operation relies on jsMapHash().
jsMapHash() can be interrupted by a TerminationException, and as a result, may
not return the string hash we are expecting. This in turn can lead to the
rehash operation hashing with wrong keys.

However, all the keys should have already been hashed. Hence, rehash() should
never see an exception thrown there. We can avoid this complication with the
TerminationException by simply calling an alternate version of jsMapHash() that
is guaranteed to never throw e.g. a jsMapHashForAlreadyHashedValue() function.

  • runtime/ExceptionHelpers.h:
  • runtime/HashMapImplInlines.h:

(JSC::jsMapHashImpl):
(JSC::jsMapHash):
(JSC::jsMapHashForAlreadyHashedValue):
(JSC::HashMapImpl<HashMapBucketType>::rehash):

Location:
trunk
Files:
1 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r276000 r276106  
     12021-04-15  Mark Lam  <mark.lam@apple.com>
     2
     3        HashMapImpl::rehash() should use a version of jsMapHash that cannot throw.
     4        https://bugs.webkit.org/show_bug.cgi?id=224610
     5        rdar://76698910
     6
     7        Reviewed by Yusuke Suzuki.
     8
     9        * stress/suppress-TerminationException-in-HashMapImpl-rehash.js: Added.
     10
    1112021-04-14  Mark Lam  <mark.lam@apple.com>
    212
  • trunk/Source/JavaScriptCore/ChangeLog

    r276102 r276106  
     12021-04-15  Mark Lam  <mark.lam@apple.com>
     2
     3        HashMapImpl::rehash() should use a version of jsMapHash that cannot throw.
     4        https://bugs.webkit.org/show_bug.cgi?id=224610
     5        rdar://76698910
     6
     7        Reviewed by Yusuke Suzuki.
     8
     9        For context, HashMapImpl::rehash()'s rehash operation relies on jsMapHash().
     10        jsMapHash() can be interrupted by a TerminationException, and as a result, may
     11        not return the string hash we are expecting.  This in turn can lead to the
     12        rehash operation hashing with wrong keys.
     13
     14        However, all the keys should have already been hashed.  Hence, rehash() should
     15        never see an exception thrown there.  We can avoid this complication with the
     16        TerminationException by simply calling an alternate version of jsMapHash() that
     17        is guaranteed to never throw e.g. a jsMapHashForAlreadyHashedValue() function.
     18
     19        * runtime/ExceptionHelpers.h:
     20        * runtime/HashMapImplInlines.h:
     21        (JSC::jsMapHashImpl):
     22        (JSC::jsMapHash):
     23        (JSC::jsMapHashForAlreadyHashedValue):
     24        (JSC::HashMapImpl<HashMapBucketType>::rehash):
     25
    1262021-04-14  Yusuke Suzuki  <ysuzuki@apple.com>
    227
  • trunk/Source/JavaScriptCore/runtime/ExceptionHelpers.h

    r275969 r276106  
    3636
    3737namespace JSC {
     38
     39enum class ExceptionExpectation {
     40    CanThrow,
     41    ShouldNotThrow
     42};
    3843
    3944typedef JSObject* (*ErrorFactory)(JSGlobalObject*, const String&, ErrorInstance::SourceAppender);
  • trunk/Source/JavaScriptCore/runtime/HashMapImplInlines.h

    r276039 r276106  
    8585}
    8686
    87 ALWAYS_INLINE uint32_t jsMapHash(JSGlobalObject* globalObject, VM& vm, JSValue value)
     87template<ExceptionExpectation expection>
     88ALWAYS_INLINE uint32_t jsMapHashImpl(JSGlobalObject* globalObject, VM& vm, JSValue value)
    8889{
    8990    ASSERT_WITH_MESSAGE(normalizeMapKey(value) == value, "We expect normalized values flowing into this function.");
     
    9293        auto scope = DECLARE_THROW_SCOPE(vm);
    9394        const String& wtfString = asString(value)->value(globalObject);
    94         RETURN_IF_EXCEPTION(scope, UINT_MAX);
     95        if constexpr (expection == ExceptionExpectation::CanThrow)
     96            RETURN_IF_EXCEPTION(scope, UINT_MAX);
     97        else
     98            EXCEPTION_ASSERT(!scope.exception());
    9599        return wtfString.impl()->hash();
    96100    }
     
    100104
    101105    return wangsInt64Hash(JSValue::encode(value));
     106}
     107
     108ALWAYS_INLINE uint32_t jsMapHash(JSGlobalObject* globalObject, VM& vm, JSValue value)
     109{
     110    return jsMapHashImpl<ExceptionExpectation::CanThrow>(globalObject, vm, value);
     111}
     112
     113ALWAYS_INLINE uint32_t jsMapHashForAlreadyHashedValue(JSGlobalObject* globalObject, VM& vm, JSValue value)
     114{
     115    return jsMapHashImpl<ExceptionExpectation::ShouldNotThrow>(globalObject, vm, value);
    102116}
    103117
     
    417431    HashMapBucketType** buffer = this->buffer();
    418432    while (iter != end) {
    419         uint32_t index = jsMapHash(globalObject, vm, iter->key()) & mask;
     433        uint32_t index = jsMapHashForAlreadyHashedValue(globalObject, vm, iter->key()) & mask;
    420434        EXCEPTION_ASSERT_WITH_MESSAGE(!scope.exception(), "All keys should already be hashed before, so this should not throw because it won't resolve ropes.");
    421435        {
Note: See TracChangeset for help on using the changeset viewer.