Changeset 282707 in webkit


Ignore:
Timestamp:
Sep 17, 2021 4:17:23 PM (10 months ago)
Author:
ysuzuki@apple.com
Message:

[JSC] Add fast property enumeration mode for JSON.stringify
https://bugs.webkit.org/show_bug.cgi?id=230393

Reviewed by Mark Lam.

JSTests:

  • stress/json-stringify-object-modify.js: Added.

(shouldBe):
(throw.new.Error.let.object.hello.get inner):
(throw.new.Error):
(shouldBe.let.object.hello.get inner):

Source/JavaScriptCore:

We collected profiles and found several subtests are using JSON.stringify enough. And generated strings are many serialized leaf objects.

This patch adds fast object property enumeration. When we know that source object meets some conditions, we can say that,
as long as structure is not changed, we can continue using property names and offset collected from the structure.
This way removes non observable Get? operations to accelerate JSON.stringify performance for major object iteration cases.

We also extend MarkedArgumentBuffer: introducing MarkedArgumentBufferWithSize which can take default inline capacity as a template
parameter. This is used in JSON.stringify to increase the buffer because now we also need to record structures in MarkedArgumentBuffer.

This offers 0.4% improvement in Speedometer2 (EmberJS-TodoMVC, Vanilla-XXX, EmberJS-Debug-TodoMVC, they have enough amount of JSON.stringify
time).


| subtest | ms | ms | b / a | pValue (significance using False Discovery Rate) |


| Elm-TodoMVC |117.710000 |117.751667 |1.000354 | 0.883246 |
| VueJS-TodoMVC |24.500000 |24.311667 |0.992313 | 0.365130 |
| EmberJS-TodoMVC |126.646667 |125.738333 |0.992828 | 0.002587 (significant) |
| BackboneJS-TodoMVC |47.873333 |47.911667 |1.000801 | 0.762509 |
| Preact-TodoMVC |17.020000 |17.070000 |1.002938 | 0.786799 |
| AngularJS-TodoMVC |129.856667 |129.353333 |0.996124 | 0.177632 |
| Vanilla-ES2015-TodoMVC |61.698333 |61.120000 |0.990626 | 0.000003 (significant) |
| Inferno-TodoMVC |62.840000 |62.496667 |0.994536 | 0.312340 |
| Flight-TodoMVC |77.095000 |76.936667 |0.997946 | 0.702724 |
| Angular2-TypeScript-TodoMVC |39.740000 |39.191667 |0.986202 | 0.053485 |
| VanillaJS-TodoMVC |49.008333 |48.346667 |0.986499 | 0.000638 (significant) |
| jQuery-TodoMVC |216.785000 |217.188333 |1.001861 | 0.270747 |
| EmberJS-Debug-TodoMVC |344.230000 |342.993333 |0.996407 | 0.012262 (significant) |
| React-TodoMVC |85.461667 |85.411667 |0.999415 | 0.758049 |
| React-Redux-TodoMVC |140.681667 |140.640000 |0.999704 | 0.871277 |
| Vanilla-ES2015-Babel-Webpack-TodoMVC |59.928333 |59.351667 |0.990377 | 0.000000 (significant) |


a mean = 264.40650
b mean = 265.51533
pValue = 0.0005567357
(Bigger means are better.)
1.004 times better
Results ARE significant

  • heap/Heap.cpp:

(JSC::Heap::addCoreConstraints):

  • heap/Heap.h:
  • heap/HeapInlines.h:
  • runtime/ArgList.cpp:

(JSC::MarkedArgumentBufferBase::addMarkSet):
(JSC::MarkedArgumentBufferBase::markLists):
(JSC::MarkedArgumentBufferBase::slowEnsureCapacity):
(JSC::MarkedArgumentBufferBase::expandCapacity):
(JSC::MarkedArgumentBufferBase::slowAppend):
(JSC::MarkedArgumentBuffer::addMarkSet): Deleted.
(JSC::MarkedArgumentBuffer::markLists): Deleted.
(JSC::MarkedArgumentBuffer::slowEnsureCapacity): Deleted.
(JSC::MarkedArgumentBuffer::expandCapacity): Deleted.
(JSC::MarkedArgumentBuffer::slowAppend): Deleted.

  • runtime/ArgList.h:

(JSC::MarkedArgumentBufferWithSize::MarkedArgumentBufferWithSize):
(JSC::MarkedArgumentBuffer::MarkedArgumentBuffer): Deleted.
(JSC::MarkedArgumentBuffer::~MarkedArgumentBuffer): Deleted.
(JSC::MarkedArgumentBuffer::size const): Deleted.
(JSC::MarkedArgumentBuffer::isEmpty const): Deleted.
(JSC::MarkedArgumentBuffer::at const): Deleted.
(JSC::MarkedArgumentBuffer::clear): Deleted.
(JSC::MarkedArgumentBuffer::appendWithAction): Deleted.
(JSC::MarkedArgumentBuffer::append): Deleted.
(JSC::MarkedArgumentBuffer::appendWithCrashOnOverflow): Deleted.
(JSC::MarkedArgumentBuffer::removeLast): Deleted.
(JSC::MarkedArgumentBuffer::last): Deleted.
(JSC::MarkedArgumentBuffer::takeLast): Deleted.
(JSC::MarkedArgumentBuffer::ensureCapacity): Deleted.
(JSC::MarkedArgumentBuffer::hasOverflowed): Deleted.
(JSC::MarkedArgumentBuffer::overflowCheckNotNeeded): Deleted.
(JSC::MarkedArgumentBuffer::fill): Deleted.
(JSC::MarkedArgumentBuffer::slotFor const): Deleted.
(JSC::MarkedArgumentBuffer::mallocBase): Deleted.
(JSC::MarkedArgumentBuffer::setNeedsOverflowCheck): Deleted.
(JSC::MarkedArgumentBuffer::clearNeedsOverflowCheck): Deleted.

  • runtime/JSONObject.cpp:

(JSC::Stringifier::Holder::hasFastObjectProperties const):
(JSC::Stringifier::appendStringifiedValue):
(JSC::Stringifier::Holder::Holder):
(JSC::Stringifier::Holder::appendNextProperty):

  • runtime/ObjectConstructorInlines.h:

(JSC::canPerformFastPropertyEnumerationForJSONStringify):

Source/WebCore:

  • Modules/webaudio/AudioWorkletProcessor.cpp:

(WebCore::AudioWorkletProcessor::buildJSArguments):

  • Modules/webaudio/AudioWorkletProcessor.h:

Source/WebKitLegacy/mac:

  • Plugins/Hosted/NetscapePluginInstanceProxy.h:
  • Plugins/Hosted/NetscapePluginInstanceProxy.mm:

(WebKit::NetscapePluginInstanceProxy::demarshalValues):

Location:
trunk
Files:
1 added
15 edited

Legend:

Unmodified
Added
Removed
  • trunk/JSTests/ChangeLog

    r282468 r282707  
     12021-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Add fast property enumeration mode for JSON.stringify
     4        https://bugs.webkit.org/show_bug.cgi?id=230393
     5
     6        Reviewed by Mark Lam.
     7
     8        * stress/json-stringify-object-modify.js: Added.
     9        (shouldBe):
     10        (throw.new.Error.let.object.hello.get inner):
     11        (throw.new.Error):
     12        (shouldBe.let.object.hello.get inner):
     13
    1142021-09-15  Yusuke Suzuki  <ysuzuki@apple.com>
    215
  • trunk/Source/JavaScriptCore/ChangeLog

    r282701 r282707  
     12021-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Add fast property enumeration mode for JSON.stringify
     4        https://bugs.webkit.org/show_bug.cgi?id=230393
     5
     6        Reviewed by Mark Lam.
     7
     8        We collected profiles and found several subtests are using JSON.stringify enough. And generated strings are many serialized leaf objects.
     9
     10        This patch adds fast object property enumeration. When we know that source object meets some conditions, we can say that,
     11        as long as structure is not changed, we can continue using property names and offset collected from the structure.
     12        This way removes non observable [[Get]] operations to accelerate JSON.stringify performance for major object iteration cases.
     13
     14        We also extend MarkedArgumentBuffer: introducing MarkedArgumentBufferWithSize which can take default inline capacity as a template
     15        parameter. This is used in JSON.stringify to increase the buffer because now we also need to record structures in MarkedArgumentBuffer.
     16
     17        This offers 0.4% improvement in Speedometer2 (EmberJS-TodoMVC, Vanilla-XXX, EmberJS-Debug-TodoMVC, they have enough amount of JSON.stringify
     18        time).
     19
     20        ----------------------------------------------------------------------------------------------------------------------------------
     21        |               subtest                |     ms      |     ms      |  b / a   | pValue (significance using False Discovery Rate) |
     22        ----------------------------------------------------------------------------------------------------------------------------------
     23        | Elm-TodoMVC                          |117.710000   |117.751667   |1.000354  | 0.883246                                         |
     24        | VueJS-TodoMVC                        |24.500000    |24.311667    |0.992313  | 0.365130                                         |
     25        | EmberJS-TodoMVC                      |126.646667   |125.738333   |0.992828  | 0.002587 (significant)                           |
     26        | BackboneJS-TodoMVC                   |47.873333    |47.911667    |1.000801  | 0.762509                                         |
     27        | Preact-TodoMVC                       |17.020000    |17.070000    |1.002938  | 0.786799                                         |
     28        | AngularJS-TodoMVC                    |129.856667   |129.353333   |0.996124  | 0.177632                                         |
     29        | Vanilla-ES2015-TodoMVC               |61.698333    |61.120000    |0.990626  | 0.000003 (significant)                           |
     30        | Inferno-TodoMVC                      |62.840000    |62.496667    |0.994536  | 0.312340                                         |
     31        | Flight-TodoMVC                       |77.095000    |76.936667    |0.997946  | 0.702724                                         |
     32        | Angular2-TypeScript-TodoMVC          |39.740000    |39.191667    |0.986202  | 0.053485                                         |
     33        | VanillaJS-TodoMVC                    |49.008333    |48.346667    |0.986499  | 0.000638 (significant)                           |
     34        | jQuery-TodoMVC                       |216.785000   |217.188333   |1.001861  | 0.270747                                         |
     35        | EmberJS-Debug-TodoMVC                |344.230000   |342.993333   |0.996407  | 0.012262 (significant)                           |
     36        | React-TodoMVC                        |85.461667    |85.411667    |0.999415  | 0.758049                                         |
     37        | React-Redux-TodoMVC                  |140.681667   |140.640000   |0.999704  | 0.871277                                         |
     38        | Vanilla-ES2015-Babel-Webpack-TodoMVC |59.928333    |59.351667    |0.990377  | 0.000000 (significant)                           |
     39        ----------------------------------------------------------------------------------------------------------------------------------
     40        a mean = 264.40650
     41        b mean = 265.51533
     42        pValue = 0.0005567357
     43        (Bigger means are better.)
     44        1.004 times better
     45        Results ARE significant
     46
     47        * heap/Heap.cpp:
     48        (JSC::Heap::addCoreConstraints):
     49        * heap/Heap.h:
     50        * heap/HeapInlines.h:
     51        * runtime/ArgList.cpp:
     52        (JSC::MarkedArgumentBufferBase::addMarkSet):
     53        (JSC::MarkedArgumentBufferBase::markLists):
     54        (JSC::MarkedArgumentBufferBase::slowEnsureCapacity):
     55        (JSC::MarkedArgumentBufferBase::expandCapacity):
     56        (JSC::MarkedArgumentBufferBase::slowAppend):
     57        (JSC::MarkedArgumentBuffer::addMarkSet): Deleted.
     58        (JSC::MarkedArgumentBuffer::markLists): Deleted.
     59        (JSC::MarkedArgumentBuffer::slowEnsureCapacity): Deleted.
     60        (JSC::MarkedArgumentBuffer::expandCapacity): Deleted.
     61        (JSC::MarkedArgumentBuffer::slowAppend): Deleted.
     62        * runtime/ArgList.h:
     63        (JSC::MarkedArgumentBufferWithSize::MarkedArgumentBufferWithSize):
     64        (JSC::MarkedArgumentBuffer::MarkedArgumentBuffer): Deleted.
     65        (JSC::MarkedArgumentBuffer::~MarkedArgumentBuffer): Deleted.
     66        (JSC::MarkedArgumentBuffer::size const): Deleted.
     67        (JSC::MarkedArgumentBuffer::isEmpty const): Deleted.
     68        (JSC::MarkedArgumentBuffer::at const): Deleted.
     69        (JSC::MarkedArgumentBuffer::clear): Deleted.
     70        (JSC::MarkedArgumentBuffer::appendWithAction): Deleted.
     71        (JSC::MarkedArgumentBuffer::append): Deleted.
     72        (JSC::MarkedArgumentBuffer::appendWithCrashOnOverflow): Deleted.
     73        (JSC::MarkedArgumentBuffer::removeLast): Deleted.
     74        (JSC::MarkedArgumentBuffer::last): Deleted.
     75        (JSC::MarkedArgumentBuffer::takeLast): Deleted.
     76        (JSC::MarkedArgumentBuffer::ensureCapacity): Deleted.
     77        (JSC::MarkedArgumentBuffer::hasOverflowed): Deleted.
     78        (JSC::MarkedArgumentBuffer::overflowCheckNotNeeded): Deleted.
     79        (JSC::MarkedArgumentBuffer::fill): Deleted.
     80        (JSC::MarkedArgumentBuffer::slotFor const): Deleted.
     81        (JSC::MarkedArgumentBuffer::mallocBase): Deleted.
     82        (JSC::MarkedArgumentBuffer::setNeedsOverflowCheck): Deleted.
     83        (JSC::MarkedArgumentBuffer::clearNeedsOverflowCheck): Deleted.
     84        * runtime/JSONObject.cpp:
     85        (JSC::Stringifier::Holder::hasFastObjectProperties const):
     86        (JSC::Stringifier::appendStringifiedValue):
     87        (JSC::Stringifier::Holder::Holder):
     88        (JSC::Stringifier::Holder::appendNextProperty):
     89        * runtime/ObjectConstructorInlines.h:
     90        (JSC::canPerformFastPropertyEnumerationForJSONStringify):
     91
    1922021-09-17  Ross Kirsling  <ross.kirsling@sony.com>
    293
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r282565 r282707  
    27682768            if (m_markListSet && m_markListSet->size()) {
    27692769                SetRootMarkReasonScope rootScope(visitor, RootMarkReason::ConservativeScan);
    2770                 MarkedArgumentBuffer::markLists(visitor, *m_markListSet);
     2770                MarkedArgumentBufferBase::markLists(visitor, *m_markListSet);
    27712771            }
    27722772
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r279861 r282707  
    7878class MarkedJSValueRefArray;
    7979class BlockDirectory;
    80 class MarkedArgumentBuffer;
     80class MarkedArgumentBufferBase;
    8181class MarkingConstraint;
    8282class MarkingConstraintSet;
     
    246246    JS_EXPORT_PRIVATE std::unique_ptr<TypeCountSet> objectTypeCounts();
    247247
    248     HashSet<MarkedArgumentBuffer*>& markListSet();
     248    HashSet<MarkedArgumentBufferBase*>& markListSet();
    249249    void addMarkedJSValueRefArray(MarkedJSValueRefArray*);
    250250   
     
    625625
    626626    ProtectCountSet m_protectedValues;
    627     std::unique_ptr<HashSet<MarkedArgumentBuffer*>> m_markListSet;
     627    std::unique_ptr<HashSet<MarkedArgumentBufferBase*>> m_markListSet;
    628628    SentinelLinkedList<MarkedJSValueRefArray, BasicRawSentinelNode<MarkedJSValueRefArray>> m_markedJSValueRefArrays;
    629629
  • trunk/Source/JavaScriptCore/heap/HeapInlines.h

    r279861 r282707  
    216216}
    217217
    218 inline HashSet<MarkedArgumentBuffer*>& Heap::markListSet()
     218inline HashSet<MarkedArgumentBufferBase*>& Heap::markListSet()
    219219{
    220220    if (!m_markListSet)
    221         m_markListSet = makeUnique<HashSet<MarkedArgumentBuffer*>>();
     221        m_markListSet = makeUnique<HashSet<MarkedArgumentBufferBase*>>();
    222222    return *m_markListSet;
    223223}
  • trunk/Source/JavaScriptCore/runtime/ArgList.cpp

    r278338 r282707  
    2828namespace JSC {
    2929
    30 void MarkedArgumentBuffer::addMarkSet(JSValue v)
     30void MarkedArgumentBufferBase::addMarkSet(JSValue v)
    3131{
    3232    if (m_markSet)
     
    5353
    5454template<typename Visitor>
    55 void MarkedArgumentBuffer::markLists(Visitor& visitor, ListSet& markSet)
     55void MarkedArgumentBufferBase::markLists(Visitor& visitor, ListSet& markSet)
    5656{
    5757    ListSet::iterator end = markSet.end();
    5858    for (ListSet::iterator it = markSet.begin(); it != end; ++it) {
    59         MarkedArgumentBuffer* list = *it;
     59        MarkedArgumentBufferBase* list = *it;
    6060        for (int i = 0; i < list->m_size; ++i)
    6161            visitor.appendUnbarriered(JSValue::decode(list->slotFor(i)));
     
    6363}
    6464
    65 template void MarkedArgumentBuffer::markLists(AbstractSlotVisitor&, ListSet&);
    66 template void MarkedArgumentBuffer::markLists(SlotVisitor&, ListSet&);
     65template void MarkedArgumentBufferBase::markLists(AbstractSlotVisitor&, ListSet&);
     66template void MarkedArgumentBufferBase::markLists(SlotVisitor&, ListSet&);
    6767
    68 void MarkedArgumentBuffer::slowEnsureCapacity(size_t requestedCapacity)
     68void MarkedArgumentBufferBase::slowEnsureCapacity(size_t requestedCapacity)
    6969{
    7070    setNeedsOverflowCheck();
     
    7575}
    7676
    77 void MarkedArgumentBuffer::expandCapacity()
     77void MarkedArgumentBufferBase::expandCapacity()
    7878{
    7979    setNeedsOverflowCheck();
     
    8484}
    8585
    86 void MarkedArgumentBuffer::expandCapacity(int newCapacity)
     86void MarkedArgumentBufferBase::expandCapacity(int newCapacity)
    8787{
    8888    setNeedsOverflowCheck();
     
    106106}
    107107
    108 void MarkedArgumentBuffer::slowAppend(JSValue v)
     108void MarkedArgumentBufferBase::slowAppend(JSValue v)
    109109{
    110110    ASSERT(m_size <= m_capacity);
  • trunk/Source/JavaScriptCore/runtime/ArgList.h

    r273138 r282707  
    2929namespace JSC {
    3030
    31 class MarkedArgumentBuffer : public RecordOverflow {
    32     WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
    33     WTF_MAKE_NONMOVABLE(MarkedArgumentBuffer);
     31class alignas(alignof(EncodedJSValue)) MarkedArgumentBufferBase : public RecordOverflow {
     32    WTF_MAKE_NONCOPYABLE(MarkedArgumentBufferBase);
     33    WTF_MAKE_NONMOVABLE(MarkedArgumentBufferBase);
    3434    WTF_FORBID_HEAP_ALLOCATION;
    3535    friend class VM;
     
    3838public:
    3939    using Base = RecordOverflow;
    40     static constexpr size_t inlineCapacity = 8;
    41     typedef HashSet<MarkedArgumentBuffer*> ListSet;
    42 
    43     // Constructor for a read-write list, to which you may append values.
    44     // FIXME: Remove all clients of this API, then remove this API.
    45     MarkedArgumentBuffer()
    46         : m_size(0)
    47         , m_capacity(inlineCapacity)
    48         , m_buffer(m_inlineBuffer)
    49         , m_markSet(nullptr)
    50     {
    51     }
    52 
    53     ~MarkedArgumentBuffer()
     40    typedef HashSet<MarkedArgumentBufferBase*> ListSet;
     41
     42    ~MarkedArgumentBufferBase()
    5443    {
    5544        ASSERT(!m_needsOverflowCheck);
     
    146135    }
    147136
     137protected:
     138    // Constructor for a read-write list, to which you may append values.
     139    // FIXME: Remove all clients of this API, then remove this API.
     140    MarkedArgumentBufferBase(size_t capacity)
     141        : m_size(0)
     142        , m_capacity(capacity)
     143        , m_buffer(inlineBuffer())
     144        , m_markSet(nullptr)
     145    {
     146    }
     147
     148    EncodedJSValue* inlineBuffer()
     149    {
     150        return bitwise_cast<EncodedJSValue*>(bitwise_cast<uint8_t*>(this) + sizeof(MarkedArgumentBufferBase));
     151    }
     152
    148153private:
    149154    void expandCapacity();
     
    162167    EncodedJSValue* mallocBase()
    163168    {
    164         if (m_buffer == m_inlineBuffer)
     169        if (m_buffer == inlineBuffer())
    165170            return nullptr;
    166171        return &slotFor(0);
     
    178183    int m_size;
    179184    int m_capacity;
    180     EncodedJSValue m_inlineBuffer[inlineCapacity];
    181185    EncodedJSValue* m_buffer;
    182186    ListSet* m_markSet;
    183187};
     188
     189template<size_t passedInlineCapacity = 8>
     190class MarkedArgumentBufferWithSize : public MarkedArgumentBufferBase {
     191public:
     192    static constexpr size_t inlineCapacity = passedInlineCapacity;
     193
     194    MarkedArgumentBufferWithSize()
     195        : MarkedArgumentBufferBase(inlineCapacity)
     196    {
     197        ASSERT(inlineBuffer() == m_inlineBuffer);
     198    }
     199
     200private:
     201    EncodedJSValue m_inlineBuffer[inlineCapacity] { };
     202};
     203
     204using MarkedArgumentBuffer = MarkedArgumentBufferWithSize<>;
    184205
    185206class ArgList {
  • trunk/Source/JavaScriptCore/runtime/JSONObject.cpp

    r281790 r282707  
    3434#include "JSCInlines.h"
    3535#include "LiteralParser.h"
    36 #include "ObjectConstructor.h"
     36#include "ObjectConstructorInlines.h"
    3737#include "PropertyNameArray.h"
    3838#include "VMInlines.h"
     
    8989    public:
    9090        enum RootHolderTag { RootHolder };
    91         Holder(JSGlobalObject*, JSObject*);
     91        Holder(JSGlobalObject*, JSObject*, Structure*);
    9292        Holder(RootHolderTag, JSObject*);
    9393
    9494        JSObject* object() const { return m_object; }
    9595        bool isArray() const { return m_isArray; }
     96        bool hasFastObjectProperties() const { return m_hasFastObjectProperties; }
    9697
    9798        bool appendNextProperty(Stringifier&, StringBuilder&);
    9899
    99100    private:
    100         JSObject* m_object;
    101         const bool m_isJSArray;
    102         const bool m_isArray;
     101        JSObject* m_object { nullptr };
     102        Structure* m_structure { nullptr };
     103        const bool m_isJSArray { false };
     104        const bool m_isArray { false };
     105        bool m_hasFastObjectProperties { false };
    103106        unsigned m_index { 0 };
    104107        unsigned m_size { 0 };
    105108        RefPtr<PropertyNameArrayData> m_propertyNames;
     109        Vector<std::tuple<Identifier, unsigned>, 8> m_propertiesAndOffsets;
    106110    };
    107111
     
    126130    String m_gap;
    127131
    128     MarkedArgumentBuffer m_objectStack;
     132    MarkedArgumentBufferWithSize<16> m_objectStack;
    129133    Vector<Holder, 16, UnsafeVectorOverflow> m_holderStack;
    130134    String m_repeatedGap;
     
    409413
    410414    bool holderStackWasEmpty = m_holderStack.isEmpty();
    411     m_holderStack.append(Holder(m_globalObject, object));
     415    Structure* structure = object->structure(vm);
     416    m_holderStack.append(Holder(m_globalObject, object, structure));
    412417    m_objectStack.appendWithCrashOnOverflow(object);
     418    m_objectStack.appendWithCrashOnOverflow(structure);
    413419    RETURN_IF_EXCEPTION(scope, StringifyFailed);
    414420    if (!holderStackWasEmpty)
     
    423429        m_holderStack.removeLast();
    424430        m_objectStack.removeLast();
     431        m_objectStack.removeLast();
    425432    } while (!m_holderStack.isEmpty());
    426433    return StringifySucceeded;
     
    456463}
    457464
    458 inline Stringifier::Holder::Holder(JSGlobalObject* globalObject, JSObject* object)
     465inline Stringifier::Holder::Holder(JSGlobalObject* globalObject, JSObject* object, Structure* structure)
    459466    : m_object(object)
     467    , m_structure(structure)
    460468    , m_isJSArray(isJSArray(object))
    461469    , m_isArray(JSC::isArray(globalObject, object))
     
    465473inline Stringifier::Holder::Holder(RootHolderTag, JSObject* object)
    466474    : m_object(object)
    467     , m_isJSArray(false)
    468     , m_isArray(false)
    469475{
    470476}
     
    491497            builder.append('[');
    492498        } else {
    493             if (stringifier.m_usingArrayReplacer)
     499            if (stringifier.m_usingArrayReplacer) {
    494500                m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data();
    495             else {
     501                m_size = m_propertyNames->propertyNameVector().size();
     502            } else if (m_structure && m_object->structureID() == m_structure->id() && canPerformFastPropertyEnumerationForJSONStringify(m_structure)) {
     503                m_structure->forEachProperty(vm, [&](const PropertyMapEntry& entry) -> bool {
     504                    if (entry.attributes & PropertyAttribute::DontEnum)
     505                        return true;
     506
     507                    PropertyName propertyName(entry.key);
     508                    if (propertyName.isSymbol())
     509                        return true;
     510                    m_propertiesAndOffsets.constructAndAppend(Identifier::fromUid(vm, entry.key), entry.offset);
     511                    return true;
     512                });
     513                m_hasFastObjectProperties = true;
     514                m_size = m_propertiesAndOffsets.size();
     515            } else {
    496516                PropertyNameArray objectPropertyNames(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude);
    497517                m_object->methodTable(vm)->getOwnPropertyNames(m_object, globalObject, objectPropertyNames, DontEnumPropertiesMode::Exclude);
    498518                RETURN_IF_EXCEPTION(scope, false);
    499519                m_propertyNames = objectPropertyNames.releaseData();
     520                m_size = m_propertyNames->propertyNameVector().size();
    500521            }
    501             m_size = m_propertyNames->propertyNameVector().size();
    502522            builder.append('{');
    503523        }
     
    539559        ASSERT(stringifyResult != StringifyFailedDueToUndefinedOrSymbolValue);
    540560    } else {
    541         // Get the value.
    542         Identifier& propertyName = m_propertyNames->propertyNameVector()[index];
    543         JSValue value = m_object->get(globalObject, propertyName);
    544         RETURN_IF_EXCEPTION(scope, false);
     561        Identifier propertyName;
     562        JSValue value;
     563        if (m_hasFastObjectProperties) {
     564            propertyName = std::get<0>(m_propertiesAndOffsets[index]);
     565            if (m_object->structureID() == m_structure->id()) {
     566                unsigned offset = std::get<1>(m_propertiesAndOffsets[index]);
     567                value = m_object->getDirect(offset);
     568            } else {
     569                value = m_object->get(globalObject, propertyName);
     570                RETURN_IF_EXCEPTION(scope, false);
     571            }
     572        } else {
     573            propertyName = m_propertyNames->propertyNameVector()[index];
     574            value = m_object->get(globalObject, propertyName);
     575            RETURN_IF_EXCEPTION(scope, false);
     576        }
    545577
    546578        rollBackPoint = builder.length();
  • trunk/Source/JavaScriptCore/runtime/ObjectConstructorInlines.h

    r279690 r282707  
    5454}
    5555
     56ALWAYS_INLINE bool canPerformFastPropertyEnumerationForJSONStringify(Structure* structure)
     57{
     58    return canPerformFastPropertyEnumerationForObjectAssign(structure);
     59}
     60
    5661ALWAYS_INLINE void objectAssignFast(VM& vm, JSObject* target, JSObject* source, Vector<RefPtr<UniquedStringImpl>, 8>& properties, MarkedArgumentBuffer& values)
    5762{
  • trunk/Source/WebCore/ChangeLog

    r282706 r282707  
     12021-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Add fast property enumeration mode for JSON.stringify
     4        https://bugs.webkit.org/show_bug.cgi?id=230393
     5
     6        Reviewed by Mark Lam.
     7
     8        * Modules/webaudio/AudioWorkletProcessor.cpp:
     9        (WebCore::AudioWorkletProcessor::buildJSArguments):
     10        * Modules/webaudio/AudioWorkletProcessor.h:
     11
    1122021-09-17  Johnson Zhou  <qiaosong_zhou@apple.com>
    213
  • trunk/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.cpp

    r274989 r282707  
    214214}
    215215
    216 void AudioWorkletProcessor::buildJSArguments(VM& vm, JSGlobalObject& globalObject, MarkedArgumentBuffer& args, const Vector<RefPtr<AudioBus>>& inputs, Vector<Ref<AudioBus>>& outputs, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap)
     216void AudioWorkletProcessor::buildJSArguments(VM& vm, JSGlobalObject& globalObject, MarkedArgumentBufferBase& args, const Vector<RefPtr<AudioBus>>& inputs, Vector<Ref<AudioBus>>& outputs, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap)
    217217{
    218218    // For performance reasons, we cache the arrays passed to JS and reconstruct them only when the topology changes.
  • trunk/Source/WebCore/Modules/webaudio/AudioWorkletProcessor.h

    r268560 r282707  
    3939namespace JSC {
    4040class JSArray;
    41 class MarkedArgumentBuffer;
     41class MarkedArgumentBufferBase;
    4242}
    4343
     
    6868private:
    6969    explicit AudioWorkletProcessor(const AudioWorkletProcessorConstructionData&);
    70     void buildJSArguments(JSC::VM&, JSC::JSGlobalObject&, JSC::MarkedArgumentBuffer&, const Vector<RefPtr<AudioBus>>& inputs, Vector<Ref<AudioBus>>& outputs, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap);
     70    void buildJSArguments(JSC::VM&, JSC::JSGlobalObject&, JSC::MarkedArgumentBufferBase&, const Vector<RefPtr<AudioBus>>& inputs, Vector<Ref<AudioBus>>& outputs, const HashMap<String, std::unique_ptr<AudioFloatArray>>& paramValuesMap);
    7171
    7272    String m_name;
  • trunk/Source/WebKitLegacy/mac/ChangeLog

    r282393 r282707  
     12021-09-17  Yusuke Suzuki  <ysuzuki@apple.com>
     2
     3        [JSC] Add fast property enumeration mode for JSON.stringify
     4        https://bugs.webkit.org/show_bug.cgi?id=230393
     5
     6        Reviewed by Mark Lam.
     7
     8        * Plugins/Hosted/NetscapePluginInstanceProxy.h:
     9        * Plugins/Hosted/NetscapePluginInstanceProxy.mm:
     10        (WebKit::NetscapePluginInstanceProxy::demarshalValues):
     11
    1122021-09-14  Chris Dumez  <cdumez@apple.com>
    213
  • trunk/Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.h

    r251425 r282707  
    311311   
    312312    bool demarshalValueFromArray(JSC::JSGlobalObject*, NSArray *array, NSUInteger& index, JSC::JSValue& result);
    313     void demarshalValues(JSC::JSGlobalObject*, data_t valuesData, mach_msg_type_number_t valuesLength, JSC::MarkedArgumentBuffer& result);
     313    void demarshalValues(JSC::JSGlobalObject*, data_t valuesData, mach_msg_type_number_t valuesLength, JSC::MarkedArgumentBufferBase& result);
    314314
    315315    class LocalObjectMap {
  • trunk/Source/WebKitLegacy/mac/Plugins/Hosted/NetscapePluginInstanceProxy.mm

    r278516 r282707  
    14341434}
    14351435
    1436 void NetscapePluginInstanceProxy::demarshalValues(JSGlobalObject* lexicalGlobalObject, data_t valuesData, mach_msg_type_number_t valuesLength, MarkedArgumentBuffer& result)
     1436void NetscapePluginInstanceProxy::demarshalValues(JSGlobalObject* lexicalGlobalObject, data_t valuesData, mach_msg_type_number_t valuesLength, MarkedArgumentBufferBase& result)
    14371437{
    14381438    RetainPtr<NSData> data = adoptNS([[NSData alloc] initWithBytesNoCopy:valuesData length:valuesLength freeWhenDone:NO]);
Note: See TracChangeset for help on using the changeset viewer.