Title: [233917] trunk/Source/_javascript_Core
Revision
233917
Author
utatane....@gmail.com
Date
2018-07-18 11:27:08 -0700 (Wed, 18 Jul 2018)

Log 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):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (233916 => 233917)


--- trunk/Source/_javascript_Core/ChangeLog	2018-07-18 18:10:08 UTC (rev 233916)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-07-18 18:27:08 UTC (rev 233917)
@@ -1,3 +1,27 @@
+2018-07-18  Yusuke Suzuki  <utatane....@gmail.com>
+
+        [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):
+
 2018-07-18  Carlos Garcia Campos  <cgar...@igalia.com>
 
         [GLIB] Add jsc_context_check_syntax() to GLib API

Modified: trunk/Source/_javascript_Core/runtime/JSONObject.cpp (233916 => 233917)


--- trunk/Source/_javascript_Core/runtime/JSONObject.cpp	2018-07-18 18:10:08 UTC (rev 233916)
+++ trunk/Source/_javascript_Core/runtime/JSONObject.cpp	2018-07-18 18:27:08 UTC (rev 233917)
@@ -120,12 +120,13 @@
     void indent();
     void unindent();
     void startNewLine(StringBuilder&) const;
+    bool isCallableReplacer() const { return m_replacerCallType != CallType::None; }
 
     ExecState* const m_exec;
     JSValue m_replacer;
-    bool m_usingArrayReplacer;
+    bool m_usingArrayReplacer { false };
     PropertyNameArray m_arrayReplacerPropertyNames;
-    CallType m_replacerCallType;
+    CallType m_replacerCallType { CallType::None };
     CallData m_replacerCallData;
     String m_gap;
 
@@ -220,9 +221,7 @@
 Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space)
     : m_exec(exec)
     , m_replacer(replacer)
-    , m_usingArrayReplacer(false)
     , m_arrayReplacerPropertyNames(&exec->vm(), PropertyNameMode::Strings, PrivateSymbolMode::Exclude)
-    , m_replacerCallType(CallType::None)
 {
     VM& vm = exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
@@ -264,12 +263,18 @@
 {
     VM& vm = m_exec->vm();
     auto scope = DECLARE_THROW_SCOPE(vm);
-    JSObject* object = constructEmptyObject(m_exec);
-    RETURN_IF_EXCEPTION(scope, jsNull());
 
     PropertyNameForFunctionCall emptyPropertyName(vm.propertyNames->emptyIdentifier);
-    object->putDirect(vm, vm.propertyNames->emptyIdentifier, value);
 
+    // If the replacer is not callable, root object wrapper is non-user-observable.
+    // We can skip creating this wrapper object.
+    JSObject* object = nullptr;
+    if (isCallableReplacer()) {
+        object = constructEmptyObject(m_exec);
+        RETURN_IF_EXCEPTION(scope, jsNull());
+        object->putDirect(vm, vm.propertyNames->emptyIdentifier, value);
+    }
+
     StringBuilder result;
     Holder root(Holder::RootHolder, object);
     auto stringifyResult = appendStringifiedValue(result, value, root, emptyPropertyName);
@@ -325,11 +330,12 @@
     RETURN_IF_EXCEPTION(scope, StringifyFailed);
 
     // Call the replacer function.
-    if (m_replacerCallType != CallType::None) {
+    if (isCallableReplacer()) {
         MarkedArgumentBuffer args;
         args.append(propertyName.value(m_exec));
         args.append(value);
         ASSERT(!args.hasOverflowed());
+        ASSERT(holder.object());
         value = call(m_exec, m_replacer, m_replacerCallType, m_replacerCallData, holder.object(), args);
         RETURN_IF_EXCEPTION(scope, StringifyFailed);
     }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to