Bug 704848 - reduce space required by nsEffectiveTLDService with more preprocessing; r=jduell
authorNathan Froyd <froydnj@mozilla.com>
Tue, 11 Sep 2012 07:42:23 -0400
changeset 106971 e7b4f8be9a4d4625bb858e8dce35c03e6aaeca80
parent 106970 a71b19fafcbe160ae40d722e2c0e8f6c014a132f
child 106972 260d140d627b762a26165a2af5d8ce53712d4270
push id14788
push usernfroyd@mozilla.com
push dateThu, 13 Sep 2012 11:25:13 +0000
treeherdermozilla-inbound@e7b4f8be9a4d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell
bugs704848
milestone18.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 704848 - reduce space required by nsEffectiveTLDService with more preprocessing; r=jduell
netwerk/build/Makefile.in
netwerk/dns/Makefile.in
netwerk/dns/nsEffectiveTLDService.cpp
netwerk/dns/nsEffectiveTLDService.h
netwerk/dns/prepare_tlds.py
--- a/netwerk/build/Makefile.in
+++ b/netwerk/build/Makefile.in
@@ -65,16 +65,17 @@ LOCAL_INCLUDES = \
   -I$(srcdir)/../base/src \
   -I$(srcdir)/../dns \
   -I$(srcdir)/../socket \
   -I$(srcdir)/../streamconv/src \
   -I$(srcdir)/../streamconv/converters \
   -I$(srcdir)/../mime \
   -I$(srcdir)/../cache \
   -I$(srcdir)/../protocol/about \
+  -I../dns \
   $(foreach d,$(filter-out about,$(NECKO_PROTOCOLS)), \
     -I$(srcdir)/../protocol/$(d)) \
   $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
     LOCAL_INCLUDES += -I$(srcdir)/../system/win32
 endif
 
--- a/netwerk/dns/Makefile.in
+++ b/netwerk/dns/Makefile.in
@@ -51,13 +51,14 @@ LOCAL_INCLUDES = \
 
 include $(topsrcdir)/config/rules.mk
 
 DEFINES += -DIMPL_NS_NET
 
 # Generate the include file containing compact, static definitions
 # for effective TLD data.
 nsEffectiveTLDService.$(OBJ_SUFFIX): etld_data.inc
+nsEffectiveTLDService.h: etld_data.inc
 
 etld_data.inc: $(srcdir)/prepare_tlds.py $(srcdir)/effective_tld_names.dat
 	$(PYTHON) $(srcdir)/prepare_tlds.py $(srcdir)/effective_tld_names.dat > etld_data.inc
 
 GARBAGE += etld_data.inc
--- a/netwerk/dns/nsEffectiveTLDService.cpp
+++ b/netwerk/dns/nsEffectiveTLDService.cpp
@@ -17,49 +17,82 @@
 #include "mozilla/FunctionTimer.h"
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS1(nsEffectiveTLDService, nsIEffectiveTLDService)
 
 // ----------------------------------------------------------------------
 
-static const ETLDEntry gEntries[] =
+#define ETLD_STR_NUM_1(line) str##line
+#define ETLD_STR_NUM(line) ETLD_STR_NUM_1(line)
+#define ETLD_ENTRY_OFFSET(name) offsetof(struct etld_string_list, ETLD_STR_NUM(__LINE__))
+
+const ETLDEntry nsDomainEntry::entries[] = {
+#define ETLD_ENTRY(name, ex, wild) { ETLD_ENTRY_OFFSET(name), ex, wild },
+#include "etld_data.inc"
+#undef ETLD_ENTRY
+};
+
+const union nsDomainEntry::etld_strings nsDomainEntry::strings = {
+  {
+#define ETLD_ENTRY(name, ex, wild) name,
 #include "etld_data.inc"
-;
+#undef ETLD_ENTRY
+  }
+};
+
+// Dummy function to statically ensure that our indices don't overflow
+// the storage provided for them.
+void
+nsDomainEntry::FuncForStaticAsserts(void)
+{
+#define ETLD_ENTRY(name, ex, wild)                                      \
+  MOZ_STATIC_ASSERT(ETLD_ENTRY_OFFSET(name) < (1 << ETLD_ENTRY_N_INDEX_BITS), \
+                    "invalid strtab index");
+#include "etld_data.inc"
+#undef ETLD_ENTRY
+}
+
+#undef ETLD_ENTRY_OFFSET
+#undef ETLD_STR_NUM
+#undef ETLD_STR_NUM1
 
 // ----------------------------------------------------------------------
 
 nsresult
 nsEffectiveTLDService::Init()
 {
   NS_TIME_FUNCTION;
 
+  const ETLDEntry *entries = nsDomainEntry::entries;
+
   // We'll probably have to rehash at least once, since nsTHashtable doesn't
   // use a perfect hash, but at least we'll save a few rehashes along the way.
   // Next optimization here is to precompute the hash using something like
   // gperf, but one step at a time.  :-)
-  mHash.Init(ArrayLength(gEntries) - 1);
+  mHash.Init(ArrayLength(nsDomainEntry::entries));
 
   nsresult rv;
   mIDNService = do_GetService(NS_IDNSERVICE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) return rv;
 
   // Initialize eTLD hash from static array
-  for (uint32_t i = 0; i < ArrayLength(gEntries) - 1; i++) {
+  for (uint32_t i = 0; i < ArrayLength(nsDomainEntry::entries); i++) {
+    const char *domain = nsDomainEntry::GetEffectiveTLDName(entries[i].strtab_index);
 #ifdef DEBUG
-    nsDependentCString name(gEntries[i].domain);
-    nsAutoCString normalizedName(gEntries[i].domain);
+    nsDependentCString name(domain);
+    nsAutoCString normalizedName(domain);
     NS_ASSERTION(NS_SUCCEEDED(NormalizeHostname(normalizedName)),
                  "normalization failure!");
     NS_ASSERTION(name.Equals(normalizedName), "domain not normalized!");
 #endif
-    nsDomainEntry *entry = mHash.PutEntry(gEntries[i].domain);
+    nsDomainEntry *entry = mHash.PutEntry(domain);
     NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
-    entry->SetData(&gEntries[i]);
+    entry->SetData(&entries[i]);
   }
   return NS_OK;
 }
 
 // External function for dealing with URI's correctly.
 // Pulls out the host portion from an nsIURI, and calls through to
 // GetPublicSuffixFromHost().
 NS_IMETHODIMP
--- a/netwerk/dns/nsEffectiveTLDService.h
+++ b/netwerk/dns/nsEffectiveTLDService.h
@@ -7,27 +7,30 @@
 
 #include "nsTHashtable.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "mozilla/Attributes.h"
 
 class nsIIDNService;
 
+#define ETLD_ENTRY_N_INDEX_BITS 30
+
 // struct for static data generated from effective_tld_names.dat
 struct ETLDEntry {
-  const char* domain;
-  bool exception;
-  bool wild;
+  uint32_t strtab_index : ETLD_ENTRY_N_INDEX_BITS;
+  uint32_t exception : 1;
+  uint32_t wild : 1;
 };
 
 
 // hash entry class
 class nsDomainEntry : public PLDHashEntryHdr
 {
+  friend class nsEffectiveTLDService;
 public:
   // Hash methods
   typedef const char* KeyType;
   typedef const char* KeyTypePointer;
 
   nsDomainEntry(KeyTypePointer aEntry)
   {
   }
@@ -40,22 +43,22 @@ public:
   }
 
   ~nsDomainEntry()
   {
   }
 
   KeyType GetKey() const
   {
-    return mData->domain;
+    return GetEffectiveTLDName(mData->strtab_index);
   }
 
   bool KeyEquals(KeyTypePointer aKey) const
   {
-    return !strcmp(mData->domain, aKey);
+    return !strcmp(GetKey(), aKey);
   }
 
   static KeyTypePointer KeyToPointer(KeyType aKey)
   {
     return aKey;
   }
 
   static PLDHashNumber HashKey(KeyTypePointer aKey)
@@ -68,18 +71,38 @@ public:
   enum { ALLOW_MEMMOVE = true };
 
   void SetData(const ETLDEntry* entry) { mData = entry; }
 
   bool IsNormal() { return mData->wild || !mData->exception; }
   bool IsException() { return mData->exception; }
   bool IsWild() { return mData->wild; }
 
+  static const char *GetEffectiveTLDName(size_t idx)
+  {
+    return strings.strtab + idx;
+  }
+
 private:
   const ETLDEntry* mData;
+#define ETLD_STR_NUM_1(line) str##line
+#define ETLD_STR_NUM(line) ETLD_STR_NUM_1(line)
+  struct etld_string_list {
+#define ETLD_ENTRY(name, ex, wild) char ETLD_STR_NUM(__LINE__)[sizeof(name)];
+#include "etld_data.inc"
+#undef ETLD_ENTRY
+  };
+  static const union etld_strings {
+    struct etld_string_list list;
+    char strtab[1];
+  } strings;
+  static const ETLDEntry entries[];
+  void FuncForStaticAsserts(void);
+#undef ETLD_STR_NUM
+#undef ETLD_STR_NUM1
 };
 
 class nsEffectiveTLDService MOZ_FINAL : public nsIEffectiveTLDService
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIEFFECTIVETLDSERVICE
 
--- a/netwerk/dns/prepare_tlds.py
+++ b/netwerk/dns/prepare_tlds.py
@@ -99,21 +99,18 @@ def main():
   """
   argv[1] is the effective TLD file to parse.
   A C++ array of { domain, exception, wild } entries representing the
   eTLD file is then printed to stdout.
   """
 
   def boolStr(b):
     if b:
-      return "PR_TRUE"
-    return "PR_FALSE"
+      return "true"
+    return "false"
 
-  print "{"
   for etld in getEffectiveTLDs(sys.argv[1]):
     exception = boolStr(etld.exception())
     wild = boolStr(etld.wild())
-    print '  { "%s", %s, %s },' % (etld.domain(), exception, wild)
-  print "  { nullptr, PR_FALSE, PR_FALSE }"
-  print "}"
+    print 'ETLD_ENTRY("%s", %s, %s)' % (etld.domain(), exception, wild)
 
 if __name__ == '__main__':
   main()