2
0
Эх сурвалжийг харах

JSONStack: Improve performance

1% Acme Air LTO gain. Majority of the time, there is at max 1 item on
the stacks and SList is too expensive to maintain 1 item in/out during
the whole JSON.stringify
Oguz Bastemur 8 жил өмнө
parent
commit
bec9475f6f

+ 76 - 6
lib/Runtime/Library/JSONStack.cpp

@@ -6,13 +6,26 @@
 #include "JSONStack.h"
 namespace JSON
 {
+#if defined(_JS_VALUE) || (_DOM_VALUE)
+#error "Something went wrong!"
+#endif
+
+#define _JS_VALUE tempValues[0]
+#define _DOM_VALUE   tempValues[1]
+
     bool StrictEqualsObjectComparer::Equals(Js::Var x, Js::Var y)
     {
         return JSONStack::Equals(x,y);
     }
 
-    JSONStack::JSONStack(ArenaAllocator *allocator, Js::ScriptContext *context) : jsObjectStack(allocator), domObjectStack(nullptr), alloc(allocator), scriptContext(context)
+    JSONStack::JSONStack(ArenaAllocator *allocator, Js::ScriptContext *context)
+      : jsObjectStack(allocator), domObjectStack(nullptr),
+        alloc(allocator), scriptContext(context)
     {
+        // most of the time, the size of the stack is 1 object.
+        // use direct member instead of expensive Push / Pop / Has
+        _JS_VALUE = nullptr;
+        _DOM_VALUE = nullptr;
     }
 
     bool JSONStack::Equals(Js::Var x, Js::Var y)
@@ -24,10 +37,18 @@ namespace JSON
     {
         if (bJsObject)
         {
+            if (_JS_VALUE)
+            {
+                return (data == _JS_VALUE);
+            }
             return jsObjectStack.Has(data);
         }
         else if (domObjectStack)
         {
+            if (_DOM_VALUE)
+            {
+                return (data == _DOM_VALUE);
+            }
             return domObjectStack->Contains(data);
         }
         return false;
@@ -37,10 +58,41 @@ namespace JSON
     {
         if (bJsObject)
         {
-            return jsObjectStack.Push(data);
+            bool result = true;
+            if (_JS_VALUE)
+            {
+                jsObjectStack.Push(_JS_VALUE);
+                _JS_VALUE = nullptr;
+            }
+
+            if (jsObjectStack.Count())
+            {
+                result = jsObjectStack.Push(data);
+            }
+            else
+            {
+                _JS_VALUE = data;
+            }
+
+            return result;
         }
+
         EnsuresDomObjectStack();
-        domObjectStack->Add(data);
+
+        if (_DOM_VALUE)
+        {
+            domObjectStack->Add(_DOM_VALUE);
+            _DOM_VALUE = nullptr;
+        }
+
+        if (domObjectStack->Count())
+        {
+            domObjectStack->Add(data);
+        }
+        else
+        {
+            _DOM_VALUE = data;
+        }
         return true;
     }
 
@@ -48,11 +100,26 @@ namespace JSON
     {
         if (bJsObject)
         {
-            jsObjectStack.Pop();
+            if (_JS_VALUE)
+            {
+                _JS_VALUE = nullptr;
+            }
+            else
+            {
+                jsObjectStack.Pop();
+            }
             return;
         }
         AssertMsg(domObjectStack != NULL, "Misaligned pop");
-        domObjectStack->RemoveAtEnd();
+
+        if (_DOM_VALUE)
+        {
+            _DOM_VALUE = nullptr;
+        }
+        else
+        {
+            domObjectStack->RemoveAtEnd();
+        }
     }
 
     void JSONStack::EnsuresDomObjectStack(void)
@@ -62,4 +129,7 @@ namespace JSON
             domObjectStack = DOMObjectStack::New(alloc);
         }
     }
-}// namespace JSON
+} // namespace JSON
+
+#undef _JS_VALUE
+#undef _DOM_VALUE

+ 7 - 0
lib/Runtime/Library/JSONStack.h

@@ -15,6 +15,7 @@ namespace JSON
     class JSONStack
     {
     private:
+        Js::Var        tempValues[2];
         SList<Js::Var> jsObjectStack; // Consider: key-only dictionary here
         typedef JsUtil::List<Js::Var, ArenaAllocator, false, Js::CopyRemovePolicy,
             SpecializedComparer<Js::Var, JSON::StrictEqualsObjectComparer>::TComparerType> DOMObjectStack;
@@ -31,6 +32,12 @@ namespace JSON
         bool Push(Js::Var data, bool bJsObject = true);
         void Pop(bool bJsObject = true);
 
+        ~JSONStack()
+        {
+            tempValues[0] = nullptr; // _JS_VALUE
+            tempValues[1] = nullptr; // _DOM_VALUE
+        }
+
     private:
         void EnsuresDomObjectStack(void);
     };