Bug 1349917 - Measuring globalBody duration draft
authorDavid Teller <dteller@mozilla.com>
Fri, 28 Apr 2017 11:04:43 +0200
changeset 570151 0d06deb36f9163d336bd9bc7caebf2b553075910
parent 570020 2286edfdeaaa6d0e7602cdb017957ee41752f2b1
child 626415 8a17e69dfd72c61405171cba87eef8eeab32c20a
push id56407
push userdteller@mozilla.com
push dateFri, 28 Apr 2017 12:11:08 +0000
bugs1349917
milestone55.0a1
Bug 1349917 - Measuring globalBody duration MozReview-Commit-ID: 4cMSCO5E5c1
js/src/frontend/BinaryAST.cpp
js/src/frontend/Parser.cpp
--- a/js/src/frontend/BinaryAST.cpp
+++ b/js/src/frontend/BinaryAST.cpp
@@ -18,49 +18,49 @@
 
 namespace js {
 namespace frontend {
 
 // #define DEBUG_HEADER 1
 
 // An abstract data structure on top of string concatenation.
 struct StringTree {
-    struct Leaf {
+    struct Data {
         const std::string data;
-        Leaf(const std::string&& data);
-        Leaf(); // Empty leaf
+        Data(const std::string&& data);
+        Data(); // Empty leaf
     };
     struct Concat {
         const mozilla::Vector<UniquePtr<StringTree>> children;
         Concat(mozilla::Vector<UniquePtr<StringTree>>&&);
     };
     enum VariantKind {
-        IsLeaf = 128,
+        IsData = 128,
         IsConcat = 129
     };
     const VariantKind variantKind;
     union Variant {
-        Leaf* leaf;
+        Data* leaf;
         Concat* concat;
-        Variant(Leaf* leaf_):
+        Variant(Data* leaf_):
             leaf(leaf_)
         {}
         Variant(Concat* concat_):
             concat(concat_)
         {}
     };
     const Variant data;
     const unsigned char kind; // Size-efficient representation of ParseNodeKind.
 
-    // Leaf constructors
-    StringTree(ParseNodeKind, Leaf* leaf);
-    static StringTree* makeLeaf(JSContext* cx, ParseNodeKind);
-    static StringTree* makeLeaf(JSContext* cx, ParseNodeKind, std::string&&);
-    bool isLeaf() const;
-    const std::string& asLeaf() const;
+    // Data constructors
+    StringTree(ParseNodeKind, Data* leaf);
+    static StringTree* makeData(JSContext* cx, ParseNodeKind);
+    static StringTree* makeData(JSContext* cx, ParseNodeKind, std::string&&);
+    bool isData() const;
+    const std::string& asData() const;
 
 
     // Concat constructors
     StringTree(ParseNodeKind, Concat* concat);
     static StringTree* makeConcat(JSContext* cx, ParseNodeKind, UniquePtr<StringTree>&& singleChild);
     static StringTree* makeConcat(JSContext* cx, ParseNodeKind, mozilla::Vector<UniquePtr<StringTree>>&& children);
 
     bool isConcat() const;
@@ -97,63 +97,63 @@ void writeUnsigned(std::ostringstream& o
     writer.writeUnsigned(value);
     out.write((const char*)writer.buffer(), writer.length());
 }
 
 // FIXME: We should rather have a StringTreeWriter.
 StringTree::~StringTree()
 {
    switch (variantKind) {
-       case VariantKind::IsLeaf:
+       case VariantKind::IsData:
            delete data.leaf;
            return;
        case VariantKind::IsConcat:
            delete data.concat;
            return;
    }
    MOZ_CRASH();
 }
 
-StringTree::StringTree(ParseNodeKind k, Leaf* leaf)
-    : variantKind(VariantKind::IsLeaf)
+StringTree::StringTree(ParseNodeKind k, Data* leaf)
+    : variantKind(VariantKind::IsData)
     , data(leaf)
     , kind(k)
 {}
 
-StringTree::Leaf::Leaf()
+StringTree::Data::Data()
     : data()
 { }
 
-StringTree::Leaf::Leaf(const std::string&& data_)
+StringTree::Data::Data(const std::string&& data_)
     : data(Move(data_))
 { }
 
 
 /*static*/ StringTree*
-StringTree::makeLeaf(JSContext* cx, ParseNodeKind kind)
+StringTree::makeData(JSContext* cx, ParseNodeKind kind)
 {
-    UniquePtr<Leaf> leaf(cx->new_<StringTree::Leaf>());
+    UniquePtr<Data> leaf(cx->new_<StringTree::Data>());
     return cx->new_<StringTree>(kind, leaf.release());
 }
 
 /*static*/ StringTree*
-StringTree::makeLeaf(JSContext* cx, ParseNodeKind kind, std::string&& data)
+StringTree::makeData(JSContext* cx, ParseNodeKind kind, std::string&& data)
 {
-    UniquePtr<Leaf> leaf(cx->new_<StringTree::Leaf>(Move(data)));
+    UniquePtr<Data> leaf(cx->new_<StringTree::Data>(Move(data)));
     return cx->new_<StringTree>(kind, leaf.release());
 }
 
 bool
-StringTree::isLeaf() const {
-    return variantKind == StringTree::VariantKind::IsLeaf;
+StringTree::isData() const {
+    return variantKind == StringTree::VariantKind::IsData;
 }
 
 const std::string&
-StringTree::asLeaf() const {
-    MOZ_ASSERT(isLeaf());
+StringTree::asData() const {
+    MOZ_ASSERT(isData());
     return data.leaf->data;
 }
 
 StringTree::StringTree(ParseNodeKind k, Concat* concat)
     : variantKind(VariantKind::IsConcat)
     , data(concat)
     , kind(k)
 {}
@@ -186,35 +186,34 @@ StringTree::asConcat() const {
     return *data.concat;
 }
 
 const mozilla::Vector<UniquePtr<StringTree>>&
 StringTree::children() const {
     return asConcat().children;
 }
 
-using Leaf = StringTree::Leaf;
+using Data = StringTree::Data;
 using Concat = StringTree::Concat;
 
 void serializeAtom(JSContext* cx, JSAtom* atom, std::string& result)
 {
     std::ostringstream out;
     if (atom) {
         RootedString string(cx, atom);
         JSAutoByteString bs;
         if (!bs.encodeUtf8(cx, string)) { // 0 terminated, right?
             MOZ_CRASH();
         }
+        MOZ_ASSERT(bs.ptr()[bs.length()] == 0);
 
         out.write(bs.ptr(), bs.length());
     } else {
-        // 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);
+        const unsigned char empty[1] = { 255 }; // Magic constant (invalid utf8 string).
+        out.write((const char*)&empty, sizeof empty);
     }
     result = Move(out.str());
 }
 
 class TreeSerializer {
 private:
     JSContext* cx;
     std::ostringstream& debug;
@@ -303,18 +302,18 @@ public:
         // Finally, write tree
         write(tree.get(), out);
 
         return true;
     }
 
 private:
     void computeOccurrences(StringTree* tree, std::unordered_map<std::string, uint32_t>& occurrences) {
-        if (tree->isLeaf()) {
-            const std::string& data = tree->asLeaf();
+        if (tree->isData()) {
+            const std::string& data = tree->asData();
             auto search = occurrences.find(data);
             if (search != occurrences.end()) {
                 search->second++;
             } else {
                 occurrences.insert({data, 1});
             }
             return;
         }
@@ -330,17 +329,17 @@ private:
         // std::cerr << "treeSerialize " << NAMES[kind] << "\n";
 #if defined(DEBUG)
         debug << NAMES[kind] << " ";
 #endif // defined(DEBUG)
 
         switch (kind) {
             // Empty tree
             case PNK_LIMIT: {
-                return StringTree::makeLeaf(cx, PNK_LIMIT);
+                return StringTree::makeData(cx, PNK_LIMIT);
             }
             // Body
             case PNK_LEXICALSCOPE:
                 // fprintf(stderr, "PNK_LEXICALSCOPE: placeholder implementation\n");
                 MOZ_FALLTHROUGH;
             case PNK_FUNCTION: {
                 UniquePtr<StringTree> body(treeSerializeAux(node->pn_body));
                 if (!body) {
@@ -515,89 +514,89 @@ private:
             }
 
             // Labels
             case PNK_BREAK: MOZ_FALLTHROUGH;
             case PNK_CONTINUE: {
                 const LoopControlStatement* cast = reinterpret_cast<const LoopControlStatement*>(node);
                 std::string label;
                 serializeAtom(cx, cast->label(), label);
-                return StringTree::makeLeaf(cx, kind, Move(label));
+                return StringTree::makeData(cx, kind, Move(label));
             }
             case PNK_LABEL: {
                 const LabeledStatement* cast = reinterpret_cast<const LabeledStatement*>(node);
                 std::string label;
                 serializeAtom(cx, cast->label(), label);
 
                 mozilla::Vector<UniquePtr<StringTree>> children;
-                if (!children.append(StringTree::makeLeaf(cx, kind, Move(label)))) {
+                if (!children.append(StringTree::makeData(cx, kind, Move(label)))) {
                     MOZ_CRASH();
                 }
                 if (!children.append(treeSerializeAux(node->pn_expr))) {
                     MOZ_CRASH();
                 }
                 return StringTree::makeConcat(cx, kind, Move(children));
             }
             case PNK_DOT: {
                 std::string label;
                 serializeAtom(cx, node->pn_atom, label);
 
                 mozilla::Vector<UniquePtr<StringTree>> children;
-                if (!children.append(StringTree::makeLeaf(cx, PNK_DOT, Move(label)))) {
+                if (!children.append(StringTree::makeData(cx, PNK_DOT, Move(label)))) {
                     MOZ_CRASH();
                 }
                 if (!children.append(treeSerializeAux(node->pn_expr))) {
                     MOZ_CRASH();
                 }
                 return StringTree::makeConcat(cx, kind, Move(children));
             }
 
             // Strings
             case PNK_NAME: MOZ_FALLTHROUGH;
             case PNK_STRING: MOZ_FALLTHROUGH;
             case PNK_TEMPLATE_STRING: {
                 std::string data;
                 serializeAtom(cx, node->pn_atom, data);
-                return StringTree::makeLeaf(cx, kind, Move(data));
+                return StringTree::makeData(cx, kind, Move(data));
             }
 
             case PNK_NUMBER: {
                 std::string data;
                 double dval = node->pn_dval;
                 data.append((const char*)&dval, sizeof(dval));
                 DecimalPoint point = node->pn_u.number.decimalPoint;
                 data.append((const char*)&point, sizeof(point));
-                return StringTree::makeLeaf(cx, kind, Move(data));
+                return StringTree::makeData(cx, kind, Move(data));
             }
 
             // Nullaries
             case PNK_TRUE: MOZ_FALLTHROUGH;
             case PNK_FALSE: MOZ_FALLTHROUGH;
             case PNK_NULL: MOZ_FALLTHROUGH;
             case PNK_RAW_UNDEFINED: MOZ_FALLTHROUGH;
             case PNK_GENERATOR: MOZ_FALLTHROUGH;
             case PNK_NOP: MOZ_FALLTHROUGH;
             case PNK_EXPORT_BATCH_SPEC: MOZ_FALLTHROUGH;
             case PNK_POSHOLDER:
-                return StringTree::makeLeaf(cx, kind);
+                return StringTree::makeData(cx, kind);
 
             // Entirely undocumented nodes:
             case PNK_MODULE: MOZ_FALLTHROUGH;
             case PNK_DEBUGGER: MOZ_FALLTHROUGH;
             case PNK_ELISION: MOZ_FALLTHROUGH;
             case PNK_OBJECT_PROPERTY_NAME: {
-                return StringTree::makeLeaf(cx, kind);
+                return StringTree::makeData(cx, kind);
             }
 
             // Stuff we don't handle yet:
             case PNK_REGEXP: {
                 // fprintf(stderr, "Placeholder %s\n", NAMES[kind]);
                 std::ostringstream placeholder("/Placeholder regexp/");
                 placeholder << debug.tellp() << "/g"; // FIXME: Just a way to make each regexp unique.
-                return StringTree::makeLeaf(cx, kind, Move(placeholder.str()));
+                return StringTree::makeData(cx, kind, Move(placeholder.str()));
             }
         }
         MOZ_CRASH("Shouldn't reach that point.");
     }
 
 public:
     void write(StringTree* tree, std::ostringstream& out) const {
         // std::cerr << "StringTree::write at " << out.tellp() << "\n";
@@ -611,22 +610,22 @@ public:
 
         // std::cerr << "StringTree::write " << NAMES[tree->kind] << "\n";
         if (tree->kind != PNK_LIMIT) {
 
     #if DEBUG_HEADER
             // std::cerr << "StringTree::write variantKind at " << out.tellp() << "\n";
             const unsigned char char_variant = tree->variantKind;
             out.write((const char*)&char_variant, sizeof char_variant);
-            MOZ_ASSERT(tree->variantKind == VariantKind::IsLeaf || tree->variantKind == VariantKind::IsConcat);
+            MOZ_ASSERT(tree->variantKind == VariantKind::IsData || tree->variantKind == VariantKind::IsConcat);
     #endif // DEBUG_HEADER
 
-            if (tree->isLeaf()) {
+            if (tree->isData()) {
                 // A leaf is a simple integer, so no byteLength.
-                const uint32_t id = getStringId(tree->asLeaf());
+                const uint32_t id = getStringId(tree->asData());
                 writeUnsigned(out, id);
             } else {
                 std::ostringstream sub_out;
 
                 const Concat& concat = tree->asConcat();
                 writeUnsigned(sub_out, concat.children.length());
                 for (const UniquePtr<StringTree>& tree: concat.children) {
                     write(tree.get(), sub_out);
@@ -655,17 +654,19 @@ public:
 };
 
 class TreeParser MOZ_RAII {
 public:
     TreeParser(JSContext* cx_, ParseNodeAllocator& alloc, std::istringstream& in_, std::ostringstream& debug_,
         BinParseOptions& options_)
         : cx(cx_)
         , in(in_)
+#if defined(DEBUG)
         , debug(debug_)
+#endif // defined(DEBUG)
         , functionDepth(0)
         , numberOfNodes(0)
         , currentByteLength((size_t)-1)
         , currentByteStart((size_t)-1)
         , currentKind((ParseNodeKind)-1)
         , currentVariant((VariantKind)-1)
         , atomsTable(cx)
         , allocator(alloc)
@@ -702,56 +703,59 @@ public:
         }
         for (const auto iter: lengthsTable) {
             std::string data;
             data.reserve(iter);
             in.read(&data[0], iter);
             if (!stringsTable.append(Move(data))) {
                 MOZ_CRASH();
             }
+            if (!atomsTable.append(nullptr)) {
+                MOZ_CRASH();
+            }
         }
 
         globalBodyStart = in.tellg();
         // std::cerr << "ParseNode: body starts at " << globalBodyStart << "\n";
 
         const mozilla::TimeStamp stringsStop = mozilla::TimeStamp::Now();
 
         std::cerr << "ReadBinaryAST strings: " << (stringsStop-start).ToMilliseconds() << "ms\n";
 
         return parseNodeAux();
     }
 
 private:
 
     // Parse a subtree as a string. The subtree must have been serialized as a string.
     // FIXME: Crappy documentation suggests crappy concepts. Clean this up.
-    uint32_t parseLeaf(ParseNodeKind& kind)
+    uint32_t parseData(ParseNodeKind& kind)
     {
-        // std::cerr << "parseLeaf\n";
+        // std::cerr << "parseData\n";
 
         const size_t previousByteLength = currentByteLength;
         const size_t previousByteStart  = currentByteStart;
         const ParseNodeKind previousKind = currentKind;
 
         // Debugging values.
         currentByteLength = -1;
         currentByteStart = -1;
         currentKind = (ParseNodeKind)-1;
 
 #if DEBUG_HEADER
         const VariantKind previousVariant = currentVariant;
 #endif // DEBUG_HEADER
         handleHeader();
 #if DEBUG_HEADER
-        MOZ_ASSERT(currentVariant == VariantKind::IsLeaf);
+        MOZ_ASSERT(currentVariant == VariantKind::IsData);
 #endif
         kind = currentKind;
         MOZ_ASSERT(currentKind != PNK_LIMIT);
 
-        const uint32_t leaf = readNodeAsLeaf();
+        const uint32_t leaf = readNodeAsData();
         handleFooter();
 
         currentByteLength = previousByteLength;
         currentByteStart = previousByteStart;
         currentKind = previousKind;
 #if DEBUG_HEADER
         currentVariant = previousVariant;
 #endif // DEBUG_HEADER
@@ -784,23 +788,23 @@ private:
 #if DEBUG_HEADER
         currentVariant = previousVariant;
 #endif // DEBUG_HEADER
 
         return result.release();
     }
 
     // Note: This should NOT be called if the kind is PNK_LIMIT.
-    uint32_t readNodeAsLeaf()
+    uint32_t readNodeAsData()
     {
         MOZ_ASSERT(currentKind != PNK_LIMIT);
 #if DEBUG_HEADER
-        MOZ_ASSERT(currentVariant == VariantKind::IsLeaf);
+        MOZ_ASSERT(currentVariant == VariantKind::IsData);
 #else
-        currentVariant = VariantKind::IsLeaf;
+        currentVariant = VariantKind::IsData;
 #endif
         currentByteStart = -1; // Ignored for leaves.
 
         return readVariableLength();
     }
 
     void skipConcatNode() {
         MOZ_ASSERT(currentKind == PNK_FUNCTION);
@@ -835,17 +839,19 @@ private:
     }
     ParseNode* freeTree(ParseNode* pn) {
         return allocator.freeTree(pn);
     }
 
 private:
     JSContext* cx;
     std::istringstream& in;
-    mozilla::DebugOnly<std::ostringstream&> debug;
+#if defined(DEBUG)
+    std::ostringstream& debug;
+#endif // defined(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;
@@ -885,35 +891,35 @@ private:
         if (char_kind >= mozilla::ArrayLength(NAMES)) {
             MOZ_CRASH("Bad kind");
         }
         currentKind = (ParseNodeKind)char_kind;
         // std::cerr << "handleHeader: " << NAMES[char_kind] << "\n";
 
         if (currentKind == PNK_LIMIT) {
             currentByteLength = 0;
-            currentVariant = VariantKind::IsLeaf;
+            currentVariant = VariantKind::IsData;
         } else {
 #if DEBUG_HEADER
             // std::cerr << "handleHeader variantKind at " << in.tellg() << "\n";
             unsigned char char_variant;
             in.read((char*)&char_variant, sizeof char_variant);
             currentVariant = (VariantKind)char_variant;
             // std::cerr << "handleHeader reading variant: " << currentVariant << "\n";
-            MOZ_ASSERT(currentVariant == VariantKind::IsLeaf || currentVariant == VariantKind::IsConcat);
+            MOZ_ASSERT(currentVariant == VariantKind::IsData || currentVariant == VariantKind::IsConcat);
 #endif // DEBUG_HEADER
         }
     }
 
     void handleFooter() {
         // std::cerr << "handleFooter " << in.tellg() << "\n";
 
         // Check byteLength, footer
 #if defined(DEBUG)
-        MOZ_ASSERT(currentVariant == VariantKind::IsConcat || currentVariant == VariantKind::IsLeaf);
+        MOZ_ASSERT(currentVariant == VariantKind::IsConcat || currentVariant == VariantKind::IsData);
         if (currentVariant == VariantKind::IsConcat) {
             const size_t byteStop = in.tellg();
             MOZ_ASSERT(byteStop - currentByteStart == currentByteLength);
         }
 #endif // defined(DEBUG)
 
 #if DEBUG_HEADER
         std::string footer(sizeof FOOTER - 1, '\0');
@@ -940,48 +946,45 @@ private:
             const uint8_t byte = (uint8_t)get;
             val |= (uint32_t(byte) >> 1) << shift;
             shift += 7;
             if (!(byte & 1))
                 return val;
         }
     }
 
-    void getLeafAsPropertyName(uint32_t id, JS::MutableHandle<PropertyName*> data)
+    void getDataAsPropertyName(uint32_t id, JS::MutableHandle<PropertyName*> data)
     {
         RootedAtom atom(cx);
-        getLeafAsAtom(id, &atom);
+        getDataAsAtom(id, &atom);
         if (atom) {
             data.set(atom->asPropertyName());
         } else {
             data.set(nullptr);
         }
     }
 
-    void getLeafAsAtom(uint32_t id, MutableHandleAtom data)
+    void getDataAsAtom(uint32_t id, MutableHandleAtom data)
     {
         if (atomsTable[id]) {
             data.set(atomsTable[id]);
             return;
         }
 
-        const std::string& leaf = getLeafAsData(id);
+        const std::string& leaf = getDataAsData(id);
 
-        // Special constant '\0\0' for empty atoms.
-        if (leaf.length() == 2) {
-            if (leaf[0] == 0 && leaf[1] == 0) {
-                data.set(nullptr);
-                return;
-            }
+        // Special constant '\255' (which is invalid utf-8) for empty atoms.
+        if (leaf.length() == 1 && (unsigned char)leaf[0] == 255) {
+            data.set(nullptr);
         }
 
         data.set(js::Atomize(cx, &leaf[0], leaf.length()));
     }
 
-    const std::string& getLeafAsData(uint32_t id)
+    const std::string& getDataAsData(uint32_t id)
     {
         return stringsTable[id];
     }
 
     MOZ_MUST_USE ParseNode* parseNode(ParseNodeKind kind)
     {
 #if defined(DEBUG)
         debug << NAMES[kind] << " ";
@@ -1202,57 +1205,57 @@ private:
 #endif // defined(DEBUG)
                 return result.release();
             }
 
             // Labels
             case PNK_BREAK: MOZ_FALLTHROUGH;
             case PNK_CONTINUE: {
                 RootedPropertyName label(cx);
-                getLeafAsPropertyName(readNodeAsLeaf(), &label);
+                getDataAsPropertyName(readNodeAsData(), &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;
                 RootedPropertyName label(cx);
-                getLeafAsPropertyName(parseLeaf(subkind), &label);
+                getDataAsPropertyName(parseData(subkind), &label);
                 MOZ_ASSERT(subkind == kind);
 
                 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: {
                 RootedAtom atom(cx);
-                getLeafAsAtom(readNodeAsLeaf(), &atom);
+                getDataAsAtom(readNodeAsData(), &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: {
-                const std::string& leaf = getLeafAsData(readNodeAsLeaf());
+                const std::string& leaf = getDataAsData(readNodeAsData());
                 std::istringstream input(leaf); // FIXME: Useless copy.
 
                 double dval;
                 input.read((char*)&dval, sizeof dval);
 
                 DecimalPoint point;
                 input.read((char*)&point, sizeof point);
 
@@ -1267,35 +1270,35 @@ private:
             case PNK_TRUE: MOZ_FALLTHROUGH;
             case PNK_FALSE: MOZ_FALLTHROUGH;
             case PNK_NULL: MOZ_FALLTHROUGH;
             case PNK_RAW_UNDEFINED: MOZ_FALLTHROUGH;
             case PNK_GENERATOR: MOZ_FALLTHROUGH;
             case PNK_NOP: MOZ_FALLTHROUGH;
             case PNK_EXPORT_BATCH_SPEC: MOZ_FALLTHROUGH;
             case PNK_POSHOLDER: {
-                mozilla::Unused << readNodeAsLeaf();
+                mozilla::Unused << readNodeAsData();
 
                 return new_<NullaryNode>(kind, JSOP_NOP, TokenPos(0, 0));
             }
 
             // Entirely undocumented nodes:
             case PNK_MODULE: MOZ_FALLTHROUGH;
             case PNK_DEBUGGER: MOZ_FALLTHROUGH;
             case PNK_ELISION: MOZ_FALLTHROUGH;
             case PNK_OBJECT_PROPERTY_NAME: {
-                mozilla::Unused << readNodeAsLeaf();
+                mozilla::Unused << readNodeAsData();
 
                 return new_<NullaryNode>(kind, JSOP_NOP, TokenPos(0, 0));
             }
 
             // Stuff we don't handle yet:
             case PNK_REGEXP: {
                 RootedAtom atom(cx);
-                getLeafAsAtom(readNodeAsLeaf(), &atom);
+                getDataAsAtom(readNodeAsData(), &atom);
 
                 return new_<RegExpLiteral>(nullptr, TokenPos(0, 0));
             }
         }
 
         MOZ_CRASH("treeParse: out of switch()");
         return nullptr;
     }
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -976,17 +976,19 @@ Parser<ParseHandler, CharT>::parse()
 
     ParseContext::VarScope varScope(this);
     if (!varScope.init(pc))
         return null();
 
     const mozilla::TimeStamp start = mozilla::TimeStamp::Now();
     Node pn = statementList(YieldIsName);
     const mozilla::TimeStamp stop = mozilla::TimeStamp::Now();
-    fprintf(stderr, "Parser<>::parse() duration: %fms\n", (stop - start).ToMilliseconds());
+    fprintf(stderr, "Parser<>::parse() %s duration: %fms\n",
+        foldConstants ? "full" : "lazy",
+        (stop - start).ToMilliseconds());
 
     if (!pn)
         return null();
 
     TokenKind tt;
     if (!tokenStream.getToken(&tt, TokenStream::Operand))
         return null();
     if (tt != TOK_EOF) {
@@ -2179,16 +2181,17 @@ Parser<FullParseHandler, char16_t>::glob
     if (!globalpc.init())
         return nullptr;
 
     ParseContext::VarScope varScope(this);
     if (!varScope.init(pc))
         return nullptr;
 
     ParseNode* body = statementList(YieldIsName);
+
     if (!body)
         return nullptr;
 
     if (!checkStatementsEOF())
         return nullptr;
 
     if (!FoldConstants(context, &body, this))
         return nullptr;