Bug 1674351 - Part 5: Add ParserAtomVectorBuilder. r=tcampbell
authorTooru Fujisawa <arai_a@mac.com>
Thu, 05 Nov 2020 15:55:57 +0000
changeset 556066 e4312f01e2d6a3b6478cf81ae92357ce145da689
parent 556065 6f1bf8c8117fa09123eaf86c59fba05fcc600f54
child 556067 f0df0bb8123db84dc77fb7d32fdf9e5045e4f0e7
push id37925
push userapavel@mozilla.com
push dateFri, 06 Nov 2020 04:14:34 +0000
treeherdermozilla-central@81a3ef82469b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1674351
milestone84.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1674351 - Part 5: Add ParserAtomVectorBuilder. r=tcampbell ParserAtomVectorBuilder is simplified version of ParserAtomsTable for XDR. This doesn't perform deduplication, and just builds vector. Differential Revision: https://phabricator.services.mozilla.com/D95843
js/src/frontend/ParserAtom.cpp
js/src/frontend/ParserAtom.h
js/src/vm/Xdr.cpp
js/src/vm/Xdr.h
--- a/js/src/frontend/ParserAtom.cpp
+++ b/js/src/frontend/ParserAtom.cpp
@@ -343,38 +343,16 @@ JS::Result<const ParserAtom*, OOM> Parse
   MOZ_ASSERT(!addPtr);
 
   ParserAtomEntry* entry;
   MOZ_TRY_VAR(entry, ParserAtomEntry::allocate<AtomCharT>(cx, alloc_, seq,
                                                           length, hash));
   return addEntry(cx, addPtr, entry);
 }
 
-template <typename AtomCharT, typename SeqCharT>
-JS::Result<const ParserAtom*, OOM> ParserAtomsTable::internChar16Seq(
-    JSContext* cx, HashNumber hash, InflatedChar16Sequence<SeqCharT> seq,
-    uint32_t length) {
-  ParserAtomEntry* entry;
-  MOZ_TRY_VAR(entry, ParserAtomEntry::allocate<AtomCharT>(cx, alloc_, seq,
-                                                          length, hash));
-
-  ParserAtomIndex index = ParserAtomIndex(entries_.length());
-  if (!entries_.append(entry)) {
-    return RaiseParserAtomsOOMError(cx);
-  }
-  SpecificParserAtomLookup<SeqCharT> lookup(seq, hash);
-  // This will be removed in later patch.
-  auto addPtr = entryMap_.lookupForAdd(lookup);
-  MOZ_ASSERT(!addPtr);
-  if (!entryMap_.add(addPtr, entry, index)) {
-    return RaiseParserAtomsOOMError(cx);
-  }
-  return entry->asAtom();
-}
-
 static const uint16_t MAX_LATIN1_CHAR = 0xff;
 
 JS::Result<const ParserAtom*, OOM> ParserAtomsTable::internAscii(
     JSContext* cx, const char* asciiPtr, uint32_t length) {
   // ASCII strings are strict subsets of Latin1 strings.
   const Latin1Char* latin1Ptr = reinterpret_cast<const Latin1Char*>(asciiPtr);
   return internLatin1(cx, latin1Ptr, length);
 }
@@ -397,41 +375,67 @@ JS::Result<const ParserAtom*, OOM> Parse
   auto addPtr = entryMap_.lookupForAdd(lookup);
   if (addPtr) {
     return addPtr->key()->asAtom();
   }
 
   return internChar16Seq<Latin1Char>(cx, addPtr, lookup.hash(), seq, length);
 }
 
-// For XDR we should only need to intern user strings so skip checks for tiny
-// and well-known atoms. As well, the atoms are unique already.
-JS::Result<const ParserAtom*, OOM> ParserAtomsTable::internLatin1ForXDR(
+ParserAtomVectorBuilder::ParserAtomVectorBuilder(JSRuntime* rt,
+                                                 LifoAlloc& alloc,
+                                                 ParserAtomVector& entries)
+    : wellKnownTable_(*rt->commonParserNames),
+      alloc_(&alloc),
+      entries_(entries) {}
+
+JS::Result<const ParserAtom*, OOM> ParserAtomVectorBuilder::internLatin1(
     JSContext* cx, const Latin1Char* latin1Ptr, HashNumber hash,
     uint32_t length) {
-  InflatedChar16Sequence<Latin1Char> seq(latin1Ptr, length);
-  SpecificParserAtomLookup<Latin1Char> lookup(seq, hash);
-
-  MOZ_ASSERT(wellKnownTable_.lookupTiny(latin1Ptr, length) == nullptr);
-  MOZ_ASSERT(wellKnownTable_.lookupChar16Seq(lookup) == nullptr);
-
-  return internChar16Seq<Latin1Char>(cx, hash, seq, length);
+  return intern<Latin1Char, Latin1Char>(cx, latin1Ptr, hash, length);
 }
 
-// Similar to internLatin1ForXDR, but char16_t is needed to represent.
-JS::Result<const ParserAtom*, OOM> ParserAtomsTable::internChar16ForXDR(
+JS::Result<const ParserAtom*, OOM> ParserAtomVectorBuilder::internChar16(
     JSContext* cx, LittleEndianChars twoByteLE, HashNumber hash,
     uint32_t length) {
+#ifdef DEBUG
   InflatedChar16Sequence<LittleEndianChars> seq(twoByteLE, length);
-  SpecificParserAtomLookup<LittleEndianChars> lookup(seq, hash);
+  bool wide = false;
+  while (seq.hasMore()) {
+    char16_t ch = seq.next();
+    if (ch > MAX_LATIN1_CHAR) {
+      wide = true;
+      break;
+    }
+  }
+  MOZ_ASSERT(wide);
+#endif
+
+  return intern<char16_t, LittleEndianChars>(cx, twoByteLE, hash, length);
+}
 
-  MOZ_ASSERT(wellKnownTable_.lookupTiny(twoByteLE, length) == nullptr);
+template <typename CharT, typename SeqCharT, typename InputCharsT>
+JS::Result<const ParserAtom*, OOM> ParserAtomVectorBuilder::intern(
+    JSContext* cx, InputCharsT chars, HashNumber hash, uint32_t length) {
+  InflatedChar16Sequence<SeqCharT> seq(chars, length);
+
+#ifdef DEBUG
+  SpecificParserAtomLookup<SeqCharT> lookup(seq);
+
+  MOZ_ASSERT(wellKnownTable_.lookupTiny(chars, length) == nullptr);
   MOZ_ASSERT(wellKnownTable_.lookupChar16Seq(lookup) == nullptr);
+#endif
 
-  return internChar16Seq<char16_t>(cx, hash, seq, length);
+  ParserAtomEntry* entry;
+  MOZ_TRY_VAR(entry,
+              ParserAtomEntry::allocate<CharT>(cx, *alloc_, seq, length, hash));
+  if (!entries_.append(entry)) {
+    return RaiseParserAtomsOOMError(cx);
+  }
+  return entry->asAtom();
 }
 
 JS::Result<const ParserAtom*, OOM> ParserAtomsTable::internUtf8(
     JSContext* cx, const mozilla::Utf8Unit* utf8Ptr, uint32_t nbyte) {
   // Check for tiny strings which are abundant in minified code.
   // NOTE: The tiny atoms are all ASCII-only so we can directly look at the
   //        UTF-8 data without worrying about surrogates.
   if (const ParserAtom* tiny = wellKnownTable_.lookupTiny(
@@ -594,17 +598,18 @@ JS::Result<const ParserAtom*, OOM> Parse
 
   // Otherwise, add new entry.
   return catLatin1 ? internChar16Seq<Latin1Char>(cx, addPtr, lookup.hash(), seq,
                                                  catLen)
                    : internChar16Seq<char16_t>(cx, addPtr, lookup.hash(), seq,
                                                catLen);
 }
 
-const ParserAtom* ParserAtomsTable::getWellKnown(WellKnownAtomId atomId) const {
+const ParserAtom* ParserAtomVectorBuilder::getWellKnown(
+    WellKnownAtomId atomId) const {
 #define ASSERT_OFFSET_(idpart, id, text)              \
   static_assert(offsetof(WellKnownParserAtoms, id) == \
                 int32_t(WellKnownAtomId::id) * sizeof(ParserAtom*));
   FOR_EACH_COMMON_PROPERTYNAME(ASSERT_OFFSET_);
 #undef ASSERT_OFFSET_
 
 #define ASSERT_OFFSET_(name, clasp)                     \
   static_assert(offsetof(WellKnownParserAtoms, name) == \
@@ -613,21 +618,23 @@ const ParserAtom* ParserAtomsTable::getW
 #undef ASSERT_OFFSET_
 
   static_assert(int32_t(WellKnownAtomId::abort) == 0,
                 "Unexpected order of WellKnownAtom");
 
   return (&wellKnownTable_.abort)[int32_t(atomId)];
 }
 
-const ParserAtom* ParserAtomsTable::getStatic1(StaticParserString1 s) const {
+const ParserAtom* ParserAtomVectorBuilder::getStatic1(
+    StaticParserString1 s) const {
   return WellKnownParserAtoms::rom_.length1Table[size_t(s)].asAtom();
 }
 
-const ParserAtom* ParserAtomsTable::getStatic2(StaticParserString2 s) const {
+const ParserAtom* ParserAtomVectorBuilder::getStatic2(
+    StaticParserString2 s) const {
   return WellKnownParserAtoms::rom_.length2Table[size_t(s)].asAtom();
 }
 
 size_t RequiredNonStaticAtomCount(const ParserAtomVector& entries) {
   size_t count = 0;
   for (const auto& entry : entries) {
     if (entry->isNotInstantiatedAndMarked() || entry->isAtomIndex()) {
       count++;
@@ -857,25 +864,24 @@ XDRResult XDRParserAtomData(XDRState<mod
   JS::Result<const ParserAtom*, JS::OOM> mbAtom(nullptr);
   if (latin1) {
     const Latin1Char* chars = nullptr;
     if (length) {
       const uint8_t* ptr = nullptr;
       MOZ_TRY(xdr->peekData(&ptr, length * sizeof(Latin1Char)));
       chars = reinterpret_cast<const Latin1Char*>(ptr);
     }
-    mbAtom = xdr->frontendAtoms().internLatin1ForXDR(cx, chars, hash, length);
+    mbAtom = xdr->frontendAtoms().internLatin1(cx, chars, hash, length);
   } else {
     const uint8_t* twoByteCharsLE = nullptr;
     if (length) {
       MOZ_TRY(xdr->peekData(&twoByteCharsLE, length * sizeof(char16_t)));
     }
     LittleEndianChars leTwoByte(twoByteCharsLE);
-    mbAtom =
-        xdr->frontendAtoms().internChar16ForXDR(cx, leTwoByte, hash, length);
+    mbAtom = xdr->frontendAtoms().internChar16(cx, leTwoByte, hash, length);
   }
 
   const ParserAtom* atom = mbAtom.unwrapOr(nullptr);
   if (!atom) {
     return xdr->fail(JS::TranscodeResult_Throw);
   }
 
   // We only transcoded ParserAtoms used for Stencils so on decode, all
--- a/js/src/frontend/ParserAtom.h
+++ b/js/src/frontend/ParserAtom.h
@@ -533,52 +533,68 @@ class ParserAtomsTable {
   // been tested.
   JS::Result<const ParserAtom*, OOM> addEntry(JSContext* cx,
                                               EntryMap::AddPtr& addPtr,
                                               ParserAtomEntry* entry);
   template <typename AtomCharT, typename SeqCharT>
   JS::Result<const ParserAtom*, OOM> internChar16Seq(
       JSContext* cx, EntryMap::AddPtr& addPtr, HashNumber hash,
       InflatedChar16Sequence<SeqCharT> seq, uint32_t length);
-  template <typename AtomCharT, typename SeqCharT>
-  JS::Result<const ParserAtom*, OOM> internChar16Seq(
-      JSContext* cx, HashNumber hash, InflatedChar16Sequence<SeqCharT> seq,
-      uint32_t length);
 
  public:
   bool empty() const { return entryMap_.empty(); }
 
   JS::Result<const ParserAtom*, OOM> internAscii(JSContext* cx,
                                                  const char* asciiPtr,
                                                  uint32_t length);
 
   JS::Result<const ParserAtom*, OOM> internLatin1(
       JSContext* cx, const JS::Latin1Char* latin1Ptr, uint32_t length);
 
-  JS::Result<const ParserAtom*, OOM> internLatin1ForXDR(
-      JSContext* cx, const JS::Latin1Char* latin1Ptr, HashNumber hash,
-      uint32_t length);
-
   JS::Result<const ParserAtom*, OOM> internUtf8(
       JSContext* cx, const mozilla::Utf8Unit* utf8Ptr, uint32_t nbyte);
 
   JS::Result<const ParserAtom*, OOM> internChar16(JSContext* cx,
                                                   const char16_t* char16Ptr,
                                                   uint32_t length);
 
-  JS::Result<const ParserAtom*, OOM> internChar16ForXDR(
-      JSContext* cx, LittleEndianChars twoByteLE, HashNumber hash,
-      uint32_t length);
-
   JS::Result<const ParserAtom*, OOM> internJSAtom(
       JSContext* cx, CompilationInfo& compilationInfo, JSAtom* atom);
 
   JS::Result<const ParserAtom*, OOM> concatAtoms(
       JSContext* cx, mozilla::Range<const ParserAtom*> atoms);
+};
 
+// Lightweight version of ParserAtomsTable.
+// This doesn't support deduplication.
+// Used while decoding XDR.
+class ParserAtomVectorBuilder {
+ private:
+  const WellKnownParserAtoms& wellKnownTable_;
+  LifoAlloc* alloc_;
+  ParserAtomVector& entries_;
+
+ public:
+  ParserAtomVectorBuilder(JSRuntime* rt, LifoAlloc& alloc,
+                          ParserAtomVector& entries);
+
+  JS::Result<const ParserAtom*, OOM> internLatin1(
+      JSContext* cx, const JS::Latin1Char* latin1Ptr, HashNumber hash,
+      uint32_t length);
+
+  JS::Result<const ParserAtom*, OOM> internChar16(
+      JSContext* cx, const LittleEndianChars twoByteLE, HashNumber hash,
+      uint32_t length);
+
+ private:
+  template <typename CharT, typename SeqCharT, typename InputCharsT>
+  JS::Result<const ParserAtom*, OOM> intern(JSContext* cx, InputCharsT chars,
+                                            HashNumber hash, uint32_t length);
+
+ public:
   const ParserAtom* getWellKnown(WellKnownAtomId atomId) const;
   const ParserAtom* getStatic1(StaticParserString1 s) const;
   const ParserAtom* getStatic2(StaticParserString2 s) const;
 };
 
 template <typename CharT>
 class SpecificParserAtomLookup : public ParserAtomLookup {
   // The sequence of characters to look up.
--- a/js/src/vm/Xdr.cpp
+++ b/js/src/vm/Xdr.cpp
@@ -747,20 +747,20 @@ XDRResult XDRIncrementalStencilEncoder::
 void XDRDecoder::trace(JSTracer* trc) { atomTable_.trace(trc); }
 
 void XDRIncrementalEncoder::trace(JSTracer* trc) { atomMap_.trace(trc); }
 
 XDRResult XDRStencilDecoder::codeStencils(
     frontend::CompilationInfoVector& compilationInfos) {
   MOZ_ASSERT(compilationInfos.delazifications.length() == 0);
 
-  frontend::ParserAtomsTable parserAtoms(
+  frontend::ParserAtomVectorBuilder parserAtomBuilder(
       cx()->runtime(), compilationInfos.initial.stencil.alloc,
       compilationInfos.initial.stencil.parserAtomData);
-  parserAtoms_ = &parserAtoms;
+  parserAtomBuilder_ = &parserAtomBuilder;
   stencilAlloc_ = &compilationInfos.initial.stencil.alloc;
 
   MOZ_TRY(codeStencil(compilationInfos.initial));
 
   if (!compilationInfos.delazifications.reserve(nchunks_ - 1)) {
     ReportOutOfMemory(cx());
     return fail(JS::TranscodeResult_Throw);
   }
@@ -768,19 +768,19 @@ XDRResult XDRStencilDecoder::codeStencil
   for (size_t i = 1; i < nchunks_; i++) {
     compilationInfos.delazifications.infallibleEmplaceBack(
         cx(), compilationInfos.initial.input.options);
     auto& funInfo = compilationInfos.delazifications[i - 1];
 
     parserAtomTable_.clear();
     hasFinishedAtomTable_ = false;
 
-    frontend::ParserAtomsTable parserAtoms(
+    frontend::ParserAtomVectorBuilder parserAtomBuilder(
         cx()->runtime(), funInfo.stencil.alloc, funInfo.stencil.parserAtomData);
-    parserAtoms_ = &parserAtoms;
+    parserAtomBuilder_ = &parserAtomBuilder;
     stencilAlloc_ = &funInfo.stencil.alloc;
 
     MOZ_TRY(codeFunctionStencil(funInfo.stencil));
   }
 
   return Ok();
 }
 
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -270,17 +270,17 @@ class XDRState : public XDRCoderBase {
   }
   virtual uint32_t& natoms() { MOZ_CRASH("does not have atomMap."); }
 
   // The number of chunks (CompilationStencils) in the buffer.
   virtual uint32_t& nchunks() { MOZ_CRASH("does not have atomMap."); }
 
   virtual bool hasAtomTable() const { return false; }
   virtual XDRAtomTable& atomTable() { MOZ_CRASH("does not have atomTable"); }
-  virtual frontend::ParserAtomsTable& frontendAtoms() {
+  virtual frontend::ParserAtomVectorBuilder& frontendAtoms() {
     MOZ_CRASH("does not have frontendAtoms");
   }
   virtual LifoAlloc& stencilAlloc() { MOZ_CRASH("does not have stencilAlloc"); }
   virtual XDRParserAtomTable& parserAtomTable() {
     // This accessor is only used when encoding stencils.
     MOZ_CRASH("does not have parserAtomTable");
   }
   virtual void finishAtomTable() { MOZ_CRASH("does not have atomTable"); }
@@ -533,31 +533,33 @@ class XDRStencilDecoder : public XDRDeco
     MOZ_ASSERT(options_);
   }
 
   uint32_t& nchunks() override { return nchunks_; }
 
   bool isForStencil() const override { return true; }
 
   bool hasAtomTable() const override { return hasFinishedAtomTable_; }
-  frontend::ParserAtomsTable& frontendAtoms() override { return *parserAtoms_; }
+  frontend::ParserAtomVectorBuilder& frontendAtoms() override {
+    return *parserAtomBuilder_;
+  }
   LifoAlloc& stencilAlloc() override { return *stencilAlloc_; }
   XDRParserAtomTable& parserAtomTable() override { return parserAtomTable_; }
   void finishAtomTable() override { hasFinishedAtomTable_ = true; }
 
   bool hasOptions() const override { return true; }
   const JS::ReadOnlyCompileOptions& options() override { return *options_; }
 
   XDRResult codeStencils(frontend::CompilationInfoVector& compilationInfos);
 
  private:
   const JS::ReadOnlyCompileOptions* options_;
   XDRParserAtomTable parserAtomTable_;
   bool hasFinishedAtomTable_ = false;
-  frontend::ParserAtomsTable* parserAtoms_ = nullptr;
+  frontend::ParserAtomVectorBuilder* parserAtomBuilder_ = nullptr;
   LifoAlloc* stencilAlloc_ = nullptr;
 };
 
 class XDROffThreadDecoder : public XDRDecoder {
   ScriptSourceObject** sourceObjectOut_;
   bool isMultiDecode_;
 
  public: