Bug 1349917 - Caching atoms draft
authorDavid Teller <dteller@mozilla.com>
Fri, 28 Apr 2017 10:56:14 +0200
changeset 570020 2286edfdeaaa6d0e7602cdb017957ee41752f2b1
parent 569947 b73d0a187da4153b5260e8763cdbf98e04ecdf3f
child 570151 0d06deb36f9163d336bd9bc7caebf2b553075910
push id56368
push userdteller@mozilla.com
push dateFri, 28 Apr 2017 08:57:14 +0000
bugs1349917
milestone55.0a1
Bug 1349917 - Caching atoms This change ensures that we do not reparse atoms at each instance. This doesn't seem to really affect performance. MozReview-Commit-ID: 7S4UxLBgLQD
js/src/frontend/BinaryAST.cpp
--- a/js/src/frontend/BinaryAST.cpp
+++ b/js/src/frontend/BinaryAST.cpp
@@ -209,41 +209,16 @@ void serializeAtom(JSContext* cx, JSAtom
         // FIXME: We could magically map this to string identifier 0. Is it worth it?
         // FIXME: This constant is poorly chosen. Pick something else that's invalid UTF-8.
         const char zero[2] = { 0, 0 }; // Magic constant (invalid utf8 string).
         out.write((const char*)&zero, sizeof zero);
     }
     result = Move(out.str());
 }
 
-JSAtom* deserializeAtom(JSContext* cx, const std::string& data)
-{
-    // Special constant '\0\0' for empty atoms.
-    if (data.length() == 2) {
-        if (data[0] == 0 && data[1] == 0) {
-            return nullptr;
-        }
-    }
-
-    return js::Atomize(cx, &data[0], data.length());
-}
-
-MOZ_MUST_USE
-bool deserializePropertyName(JSContext* cx, const std::string& data, MutableHandle<PropertyName*> label) {
-    RootedAtom atom(cx, deserializeAtom(cx, data));
-    if (atom) {
-        label.set(atom->asPropertyName());
-    } else {
-        label.set(nullptr);
-    }
-    return true;
-}
-
-// FIXME: We could make it a bit smaller by sorting strings to ensure that the
-// ones used most often have a shorter variable-length id.
 class TreeSerializer {
 private:
     JSContext* cx;
     std::ostringstream& debug;
     std::unordered_map<std::string, uint32_t> strings;
 
     uint32_t getStringId(const std::string& data) const {
         const uint32_t result = strings.find(data)->second;
@@ -687,16 +662,17 @@ public:
         , in(in_)
         , debug(debug_)
         , functionDepth(0)
         , numberOfNodes(0)
         , currentByteLength((size_t)-1)
         , currentByteStart((size_t)-1)
         , currentKind((ParseNodeKind)-1)
         , currentVariant((VariantKind)-1)
+        , atomsTable(cx)
         , allocator(alloc)
         , options(options_)
         , numberOfAllocations(0)
     {
         // std::cerr << "TreeParser starts with offset " << in.tellg() << "\n";
     }
     ~TreeParser() {
         MOZ_ASSERT(in.peek() == std::char_traits<char>::eof());
@@ -716,16 +692,19 @@ public:
                 MOZ_CRASH();
             }
         }
 
         // Read table of actual strings. Could be read lazily.
         if (!stringsTable.initCapacity(numberOfStrings)) {
             MOZ_CRASH();
         }
+        if (!atomsTable.initCapacity(numberOfStrings)) {
+            MOZ_CRASH();
+        }
         for (const auto iter: lengthsTable) {
             std::string data;
             data.reserve(iter);
             in.read(&data[0], iter);
             if (!stringsTable.append(Move(data))) {
                 MOZ_CRASH();
             }
         }
@@ -856,26 +835,27 @@ private:
     }
     ParseNode* freeTree(ParseNode* pn) {
         return allocator.freeTree(pn);
     }
 
 private:
     JSContext* cx;
     std::istringstream& in;
-    std::ostringstream& debug;
+    mozilla::DebugOnly<std::ostringstream&> debug;
     size_t functionDepth;
     size_t numberOfNodes;
     size_t currentByteLength;
     size_t currentByteStart;
     size_t globalBodyStart;
     ParseNodeKind currentKind;
     VariantKind currentVariant;
     mozilla::Vector<uint32_t> lengthsTable;
     mozilla::Vector<std::string> stringsTable;
+    GCVector<JSAtom*> atomsTable;
     ParseNodeAllocator& allocator;
     BinParseOptions options;
     size_t numberOfAllocations;
 
     JS_DECLARE_NEW_METHODS(new_, allocParseNode, inline)
 
 
     ParseNode* allocParseNode(size_t size) {
@@ -960,19 +940,50 @@ private:
             const uint8_t byte = (uint8_t)get;
             val |= (uint32_t(byte) >> 1) << shift;
             shift += 7;
             if (!(byte & 1))
                 return val;
         }
     }
 
-    void getLeafAsString(uint32_t id, std::string& data)
+    void getLeafAsPropertyName(uint32_t id, JS::MutableHandle<PropertyName*> data)
+    {
+        RootedAtom atom(cx);
+        getLeafAsAtom(id, &atom);
+        if (atom) {
+            data.set(atom->asPropertyName());
+        } else {
+            data.set(nullptr);
+        }
+    }
+
+    void getLeafAsAtom(uint32_t id, MutableHandleAtom data)
     {
-        data = stringsTable[id];
+        if (atomsTable[id]) {
+            data.set(atomsTable[id]);
+            return;
+        }
+
+        const std::string& leaf = getLeafAsData(id);
+
+        // Special constant '\0\0' for empty atoms.
+        if (leaf.length() == 2) {
+            if (leaf[0] == 0 && leaf[1] == 0) {
+                data.set(nullptr);
+                return;
+            }
+        }
+
+        data.set(js::Atomize(cx, &leaf[0], leaf.length()));
+    }
+
+    const std::string& getLeafAsData(uint32_t id)
+    {
+        return stringsTable[id];
     }
 
     MOZ_MUST_USE ParseNode* parseNode(ParseNodeKind kind)
     {
 #if defined(DEBUG)
         debug << NAMES[kind] << " ";
 #endif // defined(DEBUG)
 
@@ -1190,69 +1201,58 @@ private:
                 result->checkListConsistency();
 #endif // defined(DEBUG)
                 return result.release();
             }
 
             // Labels
             case PNK_BREAK: MOZ_FALLTHROUGH;
             case PNK_CONTINUE: {
-                std::string leaf;
-                getLeafAsString(readNodeAsLeaf(), leaf);
                 RootedPropertyName label(cx);
-                if (!deserializePropertyName(cx, leaf, &label)) {
-                    label = nullptr;
-                }
+                getLeafAsPropertyName(readNodeAsLeaf(), &label);
                 if (kind == PNK_BREAK) {
                     return new_<BreakStatement>(label, TokenPos(0, 0));
                 } else {
                     return new_<ContinueStatement>(label, TokenPos(0, 0));
                 }
             }
 
             case PNK_LABEL: MOZ_FALLTHROUGH;
             case PNK_DOT: {
                 const mozilla::DebugOnly<size_t> length = readNodeAsConcat();
                 MOZ_ASSERT(length == 2);
 
                 ParseNodeKind subkind;
-                std::string leaf;
-                getLeafAsString(parseLeaf(subkind), leaf);
+                RootedPropertyName label(cx);
+                getLeafAsPropertyName(parseLeaf(subkind), &label);
                 MOZ_ASSERT(subkind == kind);
-                RootedAtom atom(cx, deserializeAtom(cx, leaf));
 
-                RootedPropertyName label(cx);
-                if (atom) {
-                    label.set(atom->asPropertyName());
-                }
                 UniquePtr<ParseNode> expr(parseNodeAux());
                 if (kind == PNK_LABEL) {
                   return new_<LabeledStatement>(label, expr.release(), 0);
                 } else {
                   return new_<PropertyAccess>(expr.release(), label, 0, 0);
                 }
             }
 
             // Strings
             case PNK_NAME: MOZ_FALLTHROUGH;
             case PNK_STRING: MOZ_FALLTHROUGH;
             case PNK_TEMPLATE_STRING: {
-                std::string leaf;
-                getLeafAsString(readNodeAsLeaf(), leaf);
-                RootedAtom atom(cx, deserializeAtom(cx, leaf));
+                RootedAtom atom(cx);
+                getLeafAsAtom(readNodeAsLeaf(), &atom);
                 if (kind == PNK_NAME) {
                     return new_<NameNode>(kind, JSOP_NOP, atom, TokenPos(0, 0));
                 } else {
                     return new_<NullaryNode>(kind, JSOP_NOP, TokenPos(0, 0), atom);
                 }
             }
 
             case PNK_NUMBER: {
-                std::string leaf;
-                getLeafAsString(readNodeAsLeaf(), leaf);
+                const std::string& leaf = getLeafAsData(readNodeAsLeaf());
                 std::istringstream input(leaf); // FIXME: Useless copy.
 
                 double dval;
                 input.read((char*)&dval, sizeof dval);
 
                 DecimalPoint point;
                 input.read((char*)&point, sizeof point);
 
@@ -1284,18 +1284,18 @@ private:
             case PNK_OBJECT_PROPERTY_NAME: {
                 mozilla::Unused << readNodeAsLeaf();
 
                 return new_<NullaryNode>(kind, JSOP_NOP, TokenPos(0, 0));
             }
 
             // Stuff we don't handle yet:
             case PNK_REGEXP: {
-                std::string leaf;
-                getLeafAsString(readNodeAsLeaf(), leaf);
+                RootedAtom atom(cx);
+                getLeafAsAtom(readNodeAsLeaf(), &atom);
 
                 return new_<RegExpLiteral>(nullptr, TokenPos(0, 0));
             }
         }
 
         MOZ_CRASH("treeParse: out of switch()");
         return nullptr;
     }