Changeset 233917 in webkit


Ignore:
Timestamp:
Jul 18, 2018 11:27:08 AM (6 years ago)
Author:
Yusuke Suzuki
Message:

[JSC] Root wrapper object in JSON.stringify is not necessary if replacer is not callable
https://bugs.webkit.org/show_bug.cgi?id=187752

Reviewed by Mark Lam.

JSON.stringify has an implicit root wrapper object since we would like to call replacer
with a wrapper object and a property name. While we always create this wrapper object,
it is unnecessary if the given replacer is not callable.

This patch removes wrapper object creation when a replacer is not callable to avoid unnecessary
allocations. This change slightly improves the performance of Kraken/json-stringify-tinderbox.

baseline patched

json-stringify-tinderbox 39.730+-0.590 38.853+-0.266 definitely 1.0226x faster

  • runtime/JSONObject.cpp:

(JSC::Stringifier::isCallableReplacer const):
(JSC::Stringifier::Stringifier):
(JSC::Stringifier::stringify):
(JSC::Stringifier::appendStringifiedValue):

Location:
trunk/Source/JavaScriptCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r233911 r233917  
     12018-07-18  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        [JSC] Root wrapper object in JSON.stringify is not necessary if replacer is not callable
     4        https://bugs.webkit.org/show_bug.cgi?id=187752
     5
     6        Reviewed by Mark Lam.
     7
     8        JSON.stringify has an implicit root wrapper object since we would like to call replacer
     9        with a wrapper object and a property name. While we always create this wrapper object,
     10        it is unnecessary if the given replacer is not callable.
     11
     12        This patch removes wrapper object creation when a replacer is not callable to avoid unnecessary
     13        allocations. This change slightly improves the performance of Kraken/json-stringify-tinderbox.
     14
     15                                           baseline                  patched
     16
     17        json-stringify-tinderbox        39.730+-0.590      ^      38.853+-0.266         ^ definitely 1.0226x faster
     18
     19        * runtime/JSONObject.cpp:
     20        (JSC::Stringifier::isCallableReplacer const):
     21        (JSC::Stringifier::Stringifier):
     22        (JSC::Stringifier::stringify):
     23        (JSC::Stringifier::appendStringifiedValue):
     24
    1252018-07-18  Carlos Garcia Campos  <cgarcia@igalia.com>
    226
  • trunk/Source/JavaScriptCore/runtime/JSONObject.cpp

    r233122 r233917  
    121121    void unindent();
    122122    void startNewLine(StringBuilder&) const;
     123    bool isCallableReplacer() const { return m_replacerCallType != CallType::None; }
    123124
    124125    ExecState* const m_exec;
    125126    JSValue m_replacer;
    126     bool m_usingArrayReplacer;
     127    bool m_usingArrayReplacer { false };
    127128    PropertyNameArray m_arrayReplacerPropertyNames;
    128     CallType m_replacerCallType;
     129    CallType m_replacerCallType { CallType::None };
    129130    CallData m_replacerCallData;
    130131    String m_gap;
     
    221222    : m_exec(exec)
    222223    , m_replacer(replacer)
    223     , m_usingArrayReplacer(false)
    224224    , m_arrayReplacerPropertyNames(&exec->vm(), PropertyNameMode::Strings, PrivateSymbolMode::Exclude)
    225     , m_replacerCallType(CallType::None)
    226225{
    227226    VM& vm = exec->vm();
     
    265264    VM& vm = m_exec->vm();
    266265    auto scope = DECLARE_THROW_SCOPE(vm);
    267     JSObject* object = constructEmptyObject(m_exec);
    268     RETURN_IF_EXCEPTION(scope, jsNull());
    269266
    270267    PropertyNameForFunctionCall emptyPropertyName(vm.propertyNames->emptyIdentifier);
    271     object->putDirect(vm, vm.propertyNames->emptyIdentifier, value);
     268
     269    // If the replacer is not callable, root object wrapper is non-user-observable.
     270    // We can skip creating this wrapper object.
     271    JSObject* object = nullptr;
     272    if (isCallableReplacer()) {
     273        object = constructEmptyObject(m_exec);
     274        RETURN_IF_EXCEPTION(scope, jsNull());
     275        object->putDirect(vm, vm.propertyNames->emptyIdentifier, value);
     276    }
    272277
    273278    StringBuilder result;
     
    326331
    327332    // Call the replacer function.
    328     if (m_replacerCallType != CallType::None) {
     333    if (isCallableReplacer()) {
    329334        MarkedArgumentBuffer args;
    330335        args.append(propertyName.value(m_exec));
    331336        args.append(value);
    332337        ASSERT(!args.hasOverflowed());
     338        ASSERT(holder.object());
    333339        value = call(m_exec, m_replacer, m_replacerCallType, m_replacerCallData, holder.object(), args);
    334340        RETURN_IF_EXCEPTION(scope, StringifyFailed);
Note: See TracChangeset for help on using the changeset viewer.