Title: [285955] trunk/Source/_javascript_Core
Revision
285955
Author
[email protected]
Date
2021-11-17 14:51:04 -0800 (Wed, 17 Nov 2021)

Log Message

[JSC] Revise JSON.parse atomize policy
https://bugs.webkit.org/show_bug.cgi?id=233231

Reviewed by Mark Lam.

This patch improves JSON.parse performance by the following two changes.

1. Introduce JSONAtomStringCache. It is inspired from HTMLAtomStringCache. It offers cheap
   fixed-sized cache stored in VM. Since it is in VM, we do not need to clear it every time
   we call JSON.parse. We clear this cache when full GC happens. It contributes to
   flight-todomvc-json-parse by 5%.
2. Do not atomize long string. Profiling of JSON.parse said that most of time is used for
   atomizing of Strings. There is a tradeoff that, atomizing strings can reduce duplicate string
   allocations, but it has a performance penalty. V8 limits atomizing for <= 10 length strings,
   and SpiderMonkey does not atomize strings. In this patch, we aligned our atomizing policy to
   V8, so we do not atomize strings if the length is longer than 10. It contributes to
   flight-todomvc-json-parse by 50%.

Many microbenchmarks show the improvement.
                                                         ToT                     Patched

    json-parse-object-reviver-same-value           78.2683+-0.9598           77.7784+-0.9488
    vanilla-es2015-babel-webpack-todomvc-json-parse
                                                   99.9129+-0.5508     ^     85.8160+-0.8721        ^ definitely 1.1643x faster
    json-parse-array-reviver-same-value            63.5891+-0.8066           63.2895+-0.7336
    flight-todomvc-json-parse                      52.4230+-0.4474     ^     34.1159+-0.2378        ^ definitely 1.5366x faster
    json-parse-object-reviver                      80.8417+-0.5042           80.6393+-0.8087
    json-parse-leaf-object                         51.6836+-0.6754     ^     46.8983+-0.1578        ^ definitely 1.1020x faster
    vanilla-es2015-todomvc-json-parse             100.5916+-0.9399     ^     85.9522+-0.8470        ^ definitely 1.1703x faster
    vanilla-todomvc-json-parse                     76.4518+-0.4341     ^     64.2318+-0.7621        ^ definitely 1.1902x faster
    json-parse-array-reviver                       76.1276+-0.8529           75.9747+-0.9002

And Speedometer2 shows 0.8% improvement.

    ----------------------------------------------------------------------------------------------------------------------------------
    |               subtest                |     ms      |     ms      |  b / a   | pValue (significance using False Discovery Rate) |
    ----------------------------------------------------------------------------------------------------------------------------------
    | Elm-TodoMVC                          |109.046667   |108.546667   |0.995415  | 0.197186                                         |
    | VueJS-TodoMVC                        |21.813333    |21.566667    |0.988692  | 0.313141                                         |
    | EmberJS-TodoMVC                      |117.796667   |118.086667   |1.002462  | 0.558244                                         |
    | Flight-TodoMVC                       |64.273333    |62.260000    |0.968675  | 0.000000 (significant)                           |
    | BackboneJS-TodoMVC                   |42.856667    |42.863333    |1.000156  | 0.975025                                         |
    | Preact-TodoMVC                       |16.326667    |16.673333    |1.021233  | 0.298674                                         |
    | AngularJS-TodoMVC                    |123.146667   |122.413333   |0.994045  | 0.160282                                         |
    | Inferno-TodoMVC                      |57.510000    |57.533333    |1.000406  | 0.947767                                         |
    | Vanilla-ES2015-TodoMVC               |61.133333    |59.200000    |0.968375  | 0.000000 (significant)                           |
    | Angular2-TypeScript-TodoMVC          |38.863333    |38.963333    |1.002573  | 0.860359                                         |
    | VanillaJS-TodoMVC                    |51.296667    |49.423333    |0.963480  | 0.000000 (significant)                           |
    | jQuery-TodoMVC                       |210.933333   |210.596667   |0.998404  | 0.590132                                         |
    | EmberJS-Debug-TodoMVC                |326.093333   |324.890000   |0.996310  | 0.156955                                         |
    | React-TodoMVC                        |81.113333    |81.360000    |1.003041  | 0.335615                                         |
    | React-Redux-TodoMVC                  |132.560000   |132.256667   |0.997712  | 0.306072                                         |
    | Vanilla-ES2015-Babel-Webpack-TodoMVC |60.073333    |59.026667    |0.982577  | 0.000883 (significant)                           |
    ----------------------------------------------------------------------------------------------------------------------------------
    a mean = 280.29390
    b mean = 282.51413
    pValue = 0.0000083325
    (Bigger means are better.)
    1.008 times better
    Results ARE significant

* CMakeLists.txt:
* _javascript_Core.xcodeproj/project.pbxproj:
* heap/Heap.cpp:
(JSC::Heap::finalize):
* runtime/JSONAtomStringCache.h: Added.
(JSC::JSONAtomStringCache::makeIdentifier):
(JSC::JSONAtomStringCache::clear):
(JSC::JSONAtomStringCache::cacheSlot):
(JSC::JSONAtomStringCache::cache):
* runtime/JSONAtomStringCacheInlines.h: Added.
(JSC::JSONAtomStringCache::make):
(JSC::JSONAtomStringCache::vm const):
* runtime/LiteralParser.cpp:
(JSC::LiteralParser<CharType>::makeIdentifier):
(JSC::LiteralParser<CharType>::makeJSString):
(JSC::LiteralParser<CharType>::parsePrimitiveValue):
(JSC::LiteralParser<CharType>::parse):
* runtime/LiteralParser.h:
* runtime/VM.h:

Modified Paths

Added Paths

Diff

Modified: trunk/Source/_javascript_Core/CMakeLists.txt (285954 => 285955)


--- trunk/Source/_javascript_Core/CMakeLists.txt	2021-11-17 22:28:11 UTC (rev 285954)
+++ trunk/Source/_javascript_Core/CMakeLists.txt	2021-11-17 22:51:04 UTC (rev 285955)
@@ -1085,6 +1085,7 @@
     runtime/JSModuleLoader.h
     runtime/JSModuleRecord.h
     runtime/JSNativeStdFunction.h
+    runtime/JSONAtomStringCache.h
     runtime/JSONObject.h
     runtime/JSObject.h
     runtime/JSObjectInlines.h

Modified: trunk/Source/_javascript_Core/ChangeLog (285954 => 285955)


--- trunk/Source/_javascript_Core/ChangeLog	2021-11-17 22:28:11 UTC (rev 285954)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-11-17 22:51:04 UTC (rev 285955)
@@ -1,3 +1,86 @@
+2021-11-17  Yusuke Suzuki  <[email protected]>
+
+        [JSC] Revise JSON.parse atomize policy
+        https://bugs.webkit.org/show_bug.cgi?id=233231
+
+        Reviewed by Mark Lam.
+
+        This patch improves JSON.parse performance by the following two changes.
+
+        1. Introduce JSONAtomStringCache. It is inspired from HTMLAtomStringCache. It offers cheap
+           fixed-sized cache stored in VM. Since it is in VM, we do not need to clear it every time
+           we call JSON.parse. We clear this cache when full GC happens. It contributes to
+           flight-todomvc-json-parse by 5%.
+        2. Do not atomize long string. Profiling of JSON.parse said that most of time is used for
+           atomizing of Strings. There is a tradeoff that, atomizing strings can reduce duplicate string
+           allocations, but it has a performance penalty. V8 limits atomizing for <= 10 length strings,
+           and SpiderMonkey does not atomize strings. In this patch, we aligned our atomizing policy to
+           V8, so we do not atomize strings if the length is longer than 10. It contributes to
+           flight-todomvc-json-parse by 50%.
+
+        Many microbenchmarks show the improvement.
+                                                                 ToT                     Patched
+
+            json-parse-object-reviver-same-value           78.2683+-0.9598           77.7784+-0.9488
+            vanilla-es2015-babel-webpack-todomvc-json-parse
+                                                           99.9129+-0.5508     ^     85.8160+-0.8721        ^ definitely 1.1643x faster
+            json-parse-array-reviver-same-value            63.5891+-0.8066           63.2895+-0.7336
+            flight-todomvc-json-parse                      52.4230+-0.4474     ^     34.1159+-0.2378        ^ definitely 1.5366x faster
+            json-parse-object-reviver                      80.8417+-0.5042           80.6393+-0.8087
+            json-parse-leaf-object                         51.6836+-0.6754     ^     46.8983+-0.1578        ^ definitely 1.1020x faster
+            vanilla-es2015-todomvc-json-parse             100.5916+-0.9399     ^     85.9522+-0.8470        ^ definitely 1.1703x faster
+            vanilla-todomvc-json-parse                     76.4518+-0.4341     ^     64.2318+-0.7621        ^ definitely 1.1902x faster
+            json-parse-array-reviver                       76.1276+-0.8529           75.9747+-0.9002
+
+        And Speedometer2 shows 0.8% improvement.
+
+            ----------------------------------------------------------------------------------------------------------------------------------
+            |               subtest                |     ms      |     ms      |  b / a   | pValue (significance using False Discovery Rate) |
+            ----------------------------------------------------------------------------------------------------------------------------------
+            | Elm-TodoMVC                          |109.046667   |108.546667   |0.995415  | 0.197186                                         |
+            | VueJS-TodoMVC                        |21.813333    |21.566667    |0.988692  | 0.313141                                         |
+            | EmberJS-TodoMVC                      |117.796667   |118.086667   |1.002462  | 0.558244                                         |
+            | Flight-TodoMVC                       |64.273333    |62.260000    |0.968675  | 0.000000 (significant)                           |
+            | BackboneJS-TodoMVC                   |42.856667    |42.863333    |1.000156  | 0.975025                                         |
+            | Preact-TodoMVC                       |16.326667    |16.673333    |1.021233  | 0.298674                                         |
+            | AngularJS-TodoMVC                    |123.146667   |122.413333   |0.994045  | 0.160282                                         |
+            | Inferno-TodoMVC                      |57.510000    |57.533333    |1.000406  | 0.947767                                         |
+            | Vanilla-ES2015-TodoMVC               |61.133333    |59.200000    |0.968375  | 0.000000 (significant)                           |
+            | Angular2-TypeScript-TodoMVC          |38.863333    |38.963333    |1.002573  | 0.860359                                         |
+            | VanillaJS-TodoMVC                    |51.296667    |49.423333    |0.963480  | 0.000000 (significant)                           |
+            | jQuery-TodoMVC                       |210.933333   |210.596667   |0.998404  | 0.590132                                         |
+            | EmberJS-Debug-TodoMVC                |326.093333   |324.890000   |0.996310  | 0.156955                                         |
+            | React-TodoMVC                        |81.113333    |81.360000    |1.003041  | 0.335615                                         |
+            | React-Redux-TodoMVC                  |132.560000   |132.256667   |0.997712  | 0.306072                                         |
+            | Vanilla-ES2015-Babel-Webpack-TodoMVC |60.073333    |59.026667    |0.982577  | 0.000883 (significant)                           |
+            ----------------------------------------------------------------------------------------------------------------------------------
+            a mean = 280.29390
+            b mean = 282.51413
+            pValue = 0.0000083325
+            (Bigger means are better.)
+            1.008 times better
+            Results ARE significant
+
+        * CMakeLists.txt:
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * heap/Heap.cpp:
+        (JSC::Heap::finalize):
+        * runtime/JSONAtomStringCache.h: Added.
+        (JSC::JSONAtomStringCache::makeIdentifier):
+        (JSC::JSONAtomStringCache::clear):
+        (JSC::JSONAtomStringCache::cacheSlot):
+        (JSC::JSONAtomStringCache::cache):
+        * runtime/JSONAtomStringCacheInlines.h: Added.
+        (JSC::JSONAtomStringCache::make):
+        (JSC::JSONAtomStringCache::vm const):
+        * runtime/LiteralParser.cpp:
+        (JSC::LiteralParser<CharType>::makeIdentifier):
+        (JSC::LiteralParser<CharType>::makeJSString):
+        (JSC::LiteralParser<CharType>::parsePrimitiveValue):
+        (JSC::LiteralParser<CharType>::parse):
+        * runtime/LiteralParser.h:
+        * runtime/VM.h:
+
 2021-11-15  Yusuke Suzuki  <[email protected]>
 
         [JSC] Use operation path when PutByVal child1 is not speculated as a Cell

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (285954 => 285955)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2021-11-17 22:28:11 UTC (rev 285954)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2021-11-17 22:51:04 UTC (rev 285955)
@@ -1875,6 +1875,8 @@
 		E32D4DE726DAFD4300D4533A /* TemporalCalendarPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = E32D4DE126DAFD4200D4533A /* TemporalCalendarPrototype.h */; };
 		E32D4DE926DAFD4300D4533A /* TemporalCalendar.h in Headers */ = {isa = PBXBuildFile; fileRef = E32D4DE326DAFD4300D4533A /* TemporalCalendar.h */; };
 		E32D4DEA26DAFD4300D4533A /* TemporalCalendarConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = E32D4DE426DAFD4300D4533A /* TemporalCalendarConstructor.h */; };
+		E32FEA2C27448F3700FF41C1 /* JSONAtomStringCacheInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = E32FEA2A27448F3600FF41C1 /* JSONAtomStringCacheInlines.h */; };
+		E32FEA2D27448F3700FF41C1 /* JSONAtomStringCache.h in Headers */ = {isa = PBXBuildFile; fileRef = E32FEA2B27448F3600FF41C1 /* JSONAtomStringCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E33095DD23210A1B00EB7856 /* JSInternalFieldObjectImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = E33095DC23210A1400EB7856 /* JSInternalFieldObjectImpl.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E334CBB521FD96A9000EB178 /* RegExpGlobalData.h in Headers */ = {isa = PBXBuildFile; fileRef = E334CBB321FD96A9000EB178 /* RegExpGlobalData.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		E33637A61B63220200EE0840 /* ReflectObject.h in Headers */ = {isa = PBXBuildFile; fileRef = E33637A41B63220200EE0840 /* ReflectObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -5176,6 +5178,8 @@
 		E32D4DE326DAFD4300D4533A /* TemporalCalendar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemporalCalendar.h; sourceTree = "<group>"; };
 		E32D4DE426DAFD4300D4533A /* TemporalCalendarConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TemporalCalendarConstructor.h; sourceTree = "<group>"; };
 		E32D4DE526DAFD4300D4533A /* TemporalCalendarConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TemporalCalendarConstructor.cpp; sourceTree = "<group>"; };
+		E32FEA2A27448F3600FF41C1 /* JSONAtomStringCacheInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONAtomStringCacheInlines.h; sourceTree = "<group>"; };
+		E32FEA2B27448F3600FF41C1 /* JSONAtomStringCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONAtomStringCache.h; sourceTree = "<group>"; };
 		E3305FB020B0F78700CEB82B /* InByVariant.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InByVariant.cpp; sourceTree = "<group>"; };
 		E3305FB120B0F78800CEB82B /* InByVariant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InByVariant.h; sourceTree = "<group>"; };
 		E33095DC23210A1400EB7856 /* JSInternalFieldObjectImpl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSInternalFieldObjectImpl.h; sourceTree = "<group>"; };
@@ -7809,6 +7813,8 @@
 				BC22A3980E16E14800AF21C8 /* JSObject.cpp */,
 				BC22A3990E16E14800AF21C8 /* JSObject.h */,
 				0F93275E1C21EF7F00CF6564 /* JSObjectInlines.h */,
+				E32FEA2B27448F3600FF41C1 /* JSONAtomStringCache.h */,
+				E32FEA2A27448F3600FF41C1 /* JSONAtomStringCacheInlines.h */,
 				A7F9935E0FD7325100A0B2D0 /* JSONObject.cpp */,
 				A7F9935D0FD7325100A0B2D0 /* JSONObject.h */,
 				7C184E1817BEDBD3007CB63A /* JSPromise.cpp */,
@@ -10430,6 +10436,8 @@
 				0F93275F1C21EF7F00CF6564 /* JSObjectInlines.h in Headers */,
 				BC18C4250E16F5CD00B34460 /* JSObjectRef.h in Headers */,
 				A7280A2811557E3000D56957 /* JSObjectRefPrivate.h in Headers */,
+				E32FEA2D27448F3700FF41C1 /* JSONAtomStringCache.h in Headers */,
+				E32FEA2C27448F3700FF41C1 /* JSONAtomStringCacheInlines.h in Headers */,
 				A7F9935F0FD7325100A0B2D0 /* JSONObject.h in Headers */,
 				BC87CDB910712AD4000614CF /* JSONObject.lut.h in Headers */,
 				7C184E1B17BEDBD3007CB63A /* JSPromise.h in Headers */,

Modified: trunk/Source/_javascript_Core/heap/Heap.cpp (285954 => 285955)


--- trunk/Source/_javascript_Core/heap/Heap.cpp	2021-11-17 22:28:11 UTC (rev 285954)
+++ trunk/Source/_javascript_Core/heap/Heap.cpp	2021-11-17 22:51:04 UTC (rev 285955)
@@ -2048,6 +2048,9 @@
     if (HasOwnPropertyCache* cache = vm().hasOwnPropertyCache())
         cache->clear();
 
+    if (m_lastCollectionScope && m_lastCollectionScope.value() == CollectionScope::Full)
+        vm().jsonAtomStringCache.clear();
+
     immutableButterflyToStringCache.clear();
     
     for (const HeapFinalizerCallback& callback : m_heapFinalizerCallbacks)

Added: trunk/Source/_javascript_Core/runtime/JSONAtomStringCache.h (0 => 285955)


--- trunk/Source/_javascript_Core/runtime/JSONAtomStringCache.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/JSONAtomStringCache.h	2021-11-17 22:51:04 UTC (rev 285955)
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <wtf/text/AtomStringImpl.h>
+
+namespace JSC {
+
+class VM;
+
+class JSONAtomStringCache {
+public:
+    static constexpr auto maxStringLengthForCache = 32;
+    static constexpr auto capacity = 512;
+    using Cache = std::array<RefPtr<AtomStringImpl>, capacity>;
+
+    enum class Type : bool { Identifier };
+    static constexpr unsigned numberOfTypes = 1;
+
+    template<typename CharacterType>
+    ALWAYS_INLINE Ref<AtomStringImpl> makeIdentifier(const CharacterType* characters, unsigned length)
+    {
+        return make(Type::Identifier, characters, length);
+    }
+
+    ALWAYS_INLINE void clear()
+    {
+        for (unsigned i = 0; i < numberOfTypes; ++i)
+            cache(static_cast<Type>(i)).fill({ });
+    }
+
+    VM& vm() const;
+
+private:
+    template<typename CharacterType>
+    Ref<AtomStringImpl> make(Type, const CharacterType*, unsigned length);
+
+    ALWAYS_INLINE RefPtr<AtomStringImpl>& cacheSlot(Type type, UChar firstCharacter, UChar lastCharacter, UChar length)
+    {
+        unsigned hash = (firstCharacter << 6) ^ ((lastCharacter << 14) ^ firstCharacter);
+        hash += (hash >> 14) + (length << 14);
+        hash ^= hash << 14;
+        return cache(type)[(hash + (hash >> 6)) % capacity];
+    }
+
+    ALWAYS_INLINE Cache& cache(Type type) { return m_caches[static_cast<size_t>(type)]; }
+
+    Cache m_caches[numberOfTypes] { };
+};
+
+} // namespace JSC

Added: trunk/Source/_javascript_Core/runtime/JSONAtomStringCacheInlines.h (0 => 285955)


--- trunk/Source/_javascript_Core/runtime/JSONAtomStringCacheInlines.h	                        (rev 0)
+++ trunk/Source/_javascript_Core/runtime/JSONAtomStringCacheInlines.h	2021-11-17 22:51:04 UTC (rev 285955)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Identifier.h"
+#include "JSONAtomStringCache.h"
+#include "SmallStrings.h"
+#include "VM.h"
+
+namespace JSC {
+
+template<typename CharacterType>
+ALWAYS_INLINE Ref<AtomStringImpl> JSONAtomStringCache::make(Type type, const CharacterType* characters, unsigned length)
+{
+    if (!length)
+        return *static_cast<AtomStringImpl*>(StringImpl::empty());
+
+    auto firstCharacter = characters[0];
+    if (length == 1) {
+        if (firstCharacter <= maxSingleCharacterString)
+            return vm().smallStrings.singleCharacterStringRep(firstCharacter);
+    } else if (length > maxStringLengthForCache)
+        return AtomStringImpl::add(characters, length).releaseNonNull();
+
+    auto lastCharacter = characters[length - 1];
+    auto& slot = cacheSlot(type, firstCharacter, lastCharacter, length);
+    if (!equal(slot.get(), characters, length)) {
+        auto result = AtomStringImpl::add(characters, length);
+        slot = result;
+        return result.releaseNonNull();
+    }
+
+    return *slot;
+}
+
+ALWAYS_INLINE VM& JSONAtomStringCache::vm() const
+{
+    return *bitwise_cast<VM*>(bitwise_cast<uintptr_t>(this) - OBJECT_OFFSETOF(VM, jsonAtomStringCache));
+}
+
+} // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/LiteralParser.cpp (285954 => 285955)


--- trunk/Source/_javascript_Core/runtime/LiteralParser.cpp	2021-11-17 22:28:11 UTC (rev 285954)
+++ trunk/Source/_javascript_Core/runtime/LiteralParser.cpp	2021-11-17 22:51:04 UTC (rev 285955)
@@ -30,6 +30,7 @@
 #include "CodeBlock.h"
 #include "JSArray.h"
 #include "JSCInlines.h"
+#include "JSONAtomStringCacheInlines.h"
 #include "Lexer.h"
 #include "ObjectConstructor.h"
 #include <wtf/ASCIICType.h>
@@ -143,51 +144,25 @@
 }
 
 template <typename CharType>
-ALWAYS_INLINE Identifier LiteralParser<CharType>::makeIdentifier(typename Lexer::LiteralParserTokenPtr token)
+ALWAYS_INLINE Identifier LiteralParser<CharType>::makeIdentifier(VM& vm, typename Lexer::LiteralParserTokenPtr token)
 {
     if (token->stringIs8Bit)
-        return makeIdentifier(token->stringToken8, token->stringLength);
-    return makeIdentifier(token->stringToken16, token->stringLength);
+        return Identifier::fromString(vm, vm.jsonAtomStringCache.makeIdentifier(token->stringToken8, token->stringLength));
+    return Identifier::fromString(vm, vm.jsonAtomStringCache.makeIdentifier(token->stringToken16, token->stringLength));
 }
 
-    
 template <typename CharType>
-template <typename LiteralCharType>
-ALWAYS_INLINE Identifier LiteralParser<CharType>::makeIdentifier(const LiteralCharType* characters, size_t length)
+ALWAYS_INLINE JSString* LiteralParser<CharType>::makeJSString(VM& vm, typename Lexer::LiteralParserTokenPtr token)
 {
-    VM& vm = m_globalObject->vm();
-    if (!length)
-        return vm.propertyNames->emptyIdentifier;
-
-    auto firstCharacter = characters[0];
-    if (length == 1) {
-        if constexpr (sizeof(LiteralCharType) == 1)
-            return Identifier::fromString(vm, vm.smallStrings.singleCharacterStringRep(firstCharacter));
-        if (firstCharacter <= maxSingleCharacterString)
-            return Identifier::fromString(vm, vm.smallStrings.singleCharacterStringRep(firstCharacter));
-        return Identifier::fromString(vm, characters, length);
+    constexpr unsigned maxAtomizeStringLength = 10;
+    if (token->stringIs8Bit) {
+        if (token->stringLength > maxAtomizeStringLength)
+            return jsString(vm, String(token->stringToken8, token->stringLength));
+        return jsString(vm, Identifier::fromString(vm, token->stringToken8, token->stringLength).string());
     }
-
-    if (firstCharacter >= maximumCachableCharacter)
-        return Identifier::fromString(vm, characters, length);
-
-    // 0 means no entry since m_recentIdentifiersIndex is zero-filled initially.
-    uint8_t indexPlusOne = m_recentIdentifiersIndex[firstCharacter];
-    if (indexPlusOne) {
-        uint8_t index = indexPlusOne - 1;
-        auto& ident = m_recentIdentifiers[index];
-        if (Identifier::equal(ident.impl(), characters, length))
-            return ident;
-        auto result = Identifier::fromString(vm, characters, length);
-        m_recentIdentifiers[index] = result;
-        return result;
-    }
-
-    auto result = Identifier::fromString(vm, characters, length);
-    m_recentIdentifiers.uncheckedAppend(result);
-    indexPlusOne = m_recentIdentifiers.size();
-    m_recentIdentifiersIndex[firstCharacter] = indexPlusOne;
-    return result;
+    if (token->stringLength > maxAtomizeStringLength)
+        return jsString(vm, String(token->stringToken16, token->stringLength));
+    return jsString(vm, Identifier::fromString(vm, token->stringToken16, token->stringLength).string());
 }
 
 static ALWAYS_INLINE bool cannotBeIdentPartOrEscapeStart(LChar)
@@ -1144,7 +1119,7 @@
 {
     switch (m_lexer.currentToken()->type) {
     case TokString: {
-        JSValue result = jsString(vm, makeIdentifier(m_lexer.currentToken()).string());
+        JSString* result = makeJSString(vm, m_lexer.currentToken());
         m_lexer.next();
         return result;
     }
@@ -1284,7 +1259,7 @@
             TokenType type = m_lexer.next();
             if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) {
                 while (true) {
-                    Identifier ident = makeIdentifier(m_lexer.currentToken());
+                    Identifier ident = makeIdentifier(vm, m_lexer.currentToken());
 
                     if (UNLIKELY(m_lexer.next() != TokColon)) {
                         setErrorMessageForToken(TokColon);
@@ -1358,7 +1333,7 @@
                 m_parseErrorMessage = "Property name must be a string literal"_s;
                 return { };
             }
-            identifierStack.append(makeIdentifier(m_lexer.currentToken()));
+            identifierStack.append(makeIdentifier(vm, m_lexer.currentToken()));
 
             // Check for colon
             if (UNLIKELY(m_lexer.next() != TokColon)) {

Modified: trunk/Source/_javascript_Core/runtime/LiteralParser.h (285954 => 285955)


--- trunk/Source/_javascript_Core/runtime/LiteralParser.h	2021-11-17 22:28:11 UTC (rev 285954)
+++ trunk/Source/_javascript_Core/runtime/LiteralParser.h	2021-11-17 22:51:04 UTC (rev 285955)
@@ -197,9 +197,8 @@
 
     JSValue parsePrimitiveValue(VM&);
 
-    ALWAYS_INLINE Identifier makeIdentifier(typename Lexer::LiteralParserTokenPtr);
-    template<typename LiteralCharType>
-    ALWAYS_INLINE Identifier makeIdentifier(const LiteralCharType* characters, size_t length);
+    ALWAYS_INLINE Identifier makeIdentifier(VM&, typename Lexer::LiteralParserTokenPtr);
+    ALWAYS_INLINE JSString* makeJSString(VM&, typename Lexer::LiteralParserTokenPtr);
 
     void setErrorMessageForToken(TokenType);
 
@@ -208,9 +207,6 @@
     typename LiteralParser<CharType>::Lexer m_lexer;
     ParserMode m_mode;
     String m_parseErrorMessage;
-    static constexpr unsigned maximumCachableCharacter = 128;
-    std::array<uint8_t, maximumCachableCharacter> m_recentIdentifiersIndex { };
-    Vector<Identifier, maximumCachableCharacter> m_recentIdentifiers;
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/runtime/VM.h (285954 => 285955)


--- trunk/Source/_javascript_Core/runtime/VM.h	2021-11-17 22:28:11 UTC (rev 285954)
+++ trunk/Source/_javascript_Core/runtime/VM.h	2021-11-17 22:51:04 UTC (rev 285955)
@@ -47,6 +47,7 @@
 #include "JSCJSValue.h"
 #include "JSDateMath.h"
 #include "JSLock.h"
+#include "JSONAtomStringCache.h"
 #include "MacroAssemblerCodeRef.h"
 #include "Microtask.h"
 #include "NumericStrings.h"
@@ -805,6 +806,7 @@
     std::unique_ptr<SimpleStats> machineCodeBytesPerBytecodeWordForBaselineJIT;
     WeakGCMap<StringImpl*, JSString, PtrHash<StringImpl*>> stringCache;
     Strong<JSString> lastCachedString;
+    JSONAtomStringCache jsonAtomStringCache;
 
     AtomStringTable* atomStringTable() const { return m_atomStringTable; }
     WTF::SymbolRegistry& symbolRegistry() { return m_symbolRegistry; }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to