Ignore:
Timestamp:
Sep 21, 2020, 3:10:24 PM (5 years ago)
Author:
[email protected]
Message:

[JSC] BigInt should work with Map / Set
https://bugs.webkit.org/show_bug.cgi?id=216667
JSTests:

<rdar://problem/69107221>

Reviewed by Robin Morisset.

  • stress/bigint-and-map-set.js: Added.

(shouldBe):
(opaque1n):
(testMap):
(let.set new):

  • stress/bigint-string-map-set.js: Added.

(shouldBe):
(testMap):

  • stress/bigint32-map-set.js: Added.

(shouldBe):
(testMap):

Source/JavaScriptCore:

Reviewed by Robin Morisset.

This patch makes BigInt supported in Map / Set.

  1. In NormalizeMapKey, we always attempt to convert HeapBigInt to BigInt32 (if supported). So we ensure that,

normalized BigInt has one unique form for BigInt32 range. This allows us to use hashing for BigInt32 bit pattern directly.

  1. In MapHash, for BigInt32, we directly has the JSValue bits. For HeapBigInt, we calculate hash via Hasher.
  2. In GetMapBucket, we consider HeapBigInt case correctly.
  • dfg/DFGAbstractInterpreterInlines.h:

(JSC::DFG::AbstractInterpreter<AbstractStateType>::executeEffects):

  • dfg/DFGConstantFoldingPhase.cpp:

(JSC::DFG::ConstantFoldingPhase::foldConstants):

  • dfg/DFGDoesGC.cpp:

(JSC::DFG::doesGC):

  • dfg/DFGFixupPhase.cpp:

(JSC::DFG::FixupPhase::fixupNode):
(JSC::DFG::FixupPhase::fixupNormalizeMapKey):

  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::compileNormalizeMapKey):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • ftl/FTLLowerDFGToB3.cpp:

(JSC::FTL::DFG::LowerDFGToB3::compileMapHash):
(JSC::FTL::DFG::LowerDFGToB3::compileNormalizeMapKey):
(JSC::FTL::DFG::LowerDFGToB3::compileGetMapBucket):

  • runtime/HashMapImpl.h:

(JSC::normalizeMapKey):
(JSC::jsMapHash):
(JSC::concurrentJSMapHash):

  • runtime/JSBigInt.cpp:

(JSC::JSBigInt::concurrentHash):

  • runtime/JSBigInt.h:

(JSC::tryConvertToBigInt32):

Source/WebCore:

<rdar://problem/69107221>

Reviewed by Robin Morisset.

Strongly ensure that BigInt32 is always selected since Map / Set could use it as a key.

  • bindings/js/SerializedScriptValue.cpp:

(WebCore::CloneDeserializer::readBigInt):

Source/WTF:

Reviewed by Robin Morisset.

  • wtf/Hasher.h:

(WTF::Hasher::hash const):
(WTF::add):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/JSBigInt.h

    r266795 r267373  
    428428    JS_EXPORT_PRIVATE JSBigInt* tryRightTrim(VM&);
    429429
     430    JS_EXPORT_PRIVATE Optional<unsigned> concurrentHash();
     431    unsigned hash()
     432    {
     433        if (m_hash)
     434            return m_hash;
     435        return hashSlow();
     436    }
     437
    430438private:
    431439    JSBigInt(VM&, Structure*, Digit*, unsigned length);
    432440
    433441    JSBigInt* rightTrim(JSGlobalObject*, VM&);
     442
     443    JS_EXPORT_PRIVATE unsigned hashSlow();
    434444
    435445    static JSBigInt* createFromImpl(JSGlobalObject*, uint64_t value, bool sign);
     
    573583
    574584    inline Digit* dataStorage() { return m_data.get(m_length); }
     585    inline Digit* dataStorageUnsafe() { return m_data.getUnsafe(); }
    575586
    576587    const unsigned m_length;
     588    unsigned m_hash { 0 };
    577589    bool m_sign { false };
    578590    CagedBarrierPtr<Gigacage::Primitive, Digit, tagCagedPtr> m_data;
     
    609621}
    610622
     623ALWAYS_INLINE JSValue tryConvertToBigInt32(JSBigInt* bigInt)
     624{
     625#if USE(BIGINT32)
     626    if (UNLIKELY(!bigInt))
     627        return JSValue();
     628
     629    if (bigInt->length() <= 1) {
     630        if (!bigInt->length())
     631            return jsBigInt32(0);
     632        JSBigInt::Digit digit = bigInt->digit(0);
     633        if (bigInt->sign()) {
     634            static constexpr uint64_t maxValue = -static_cast<int64_t>(std::numeric_limits<int32_t>::min());
     635            if (digit <= maxValue)
     636                return jsBigInt32(static_cast<int32_t>(-static_cast<int64_t>(digit)));
     637        } else {
     638            static constexpr uint64_t maxValue = static_cast<uint64_t>(std::numeric_limits<int32_t>::max());
     639            if (digit <= maxValue)
     640                return jsBigInt32(static_cast<int32_t>(digit));
     641        }
     642    }
     643#endif
     644
     645    return bigInt;
     646}
     647
    611648} // namespace JSC
Note: See TracChangeset for help on using the changeset viewer.