Bug 711563 - flatten property and function names; r=jorendorff
authorNathan Froyd <froydnj@mozilla.com>
Thu, 29 Dec 2011 16:20:26 -0500
changeset 85803 dbb0ed6a5a6f0000b7c2280e9143097c3e812345
parent 85802 1f327a1c588b76be1b4c26a3973805511b84739a
child 85804 9cf47a611458a7e53639aee78c33450ef4ed092b
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs711563
milestone12.0a1
Bug 711563 - flatten property and function names; r=jorendorff
js/xpconnect/src/XPCQuickStubs.cpp
js/xpconnect/src/XPCQuickStubs.h
js/xpconnect/src/qsgen.py
--- a/js/xpconnect/src/XPCQuickStubs.cpp
+++ b/js/xpconnect/src/XPCQuickStubs.cpp
@@ -386,17 +386,18 @@ SharedDefineSetter(JSContext *cx, uintN 
 }
 
 
 JSBool
 xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, uintN flags,
                        PRUint32 ifacec, const nsIID **interfaces,
                        PRUint32 tableSize, const xpc_qsHashEntry *table,
                        const xpc_qsPropertySpec *propspecs,
-                       const xpc_qsFunctionSpec *funcspecs)
+                       const xpc_qsFunctionSpec *funcspecs,
+                       const char *stringTable)
 {
     /*
      * Walk interfaces in reverse order to behave like XPConnect when a
      * feature is defined in more than one of the interfaces.
      *
      * XPCNativeSet::FindMethod returns the first matching feature it finds,
      * searching the interfaces forward.  Here, definitions toward the
      * front of 'interfaces' overwrite those toward the back.
@@ -409,27 +410,29 @@ xpc_qsDefineQuickStubs(JSContext *cx, JS
 
         if (entry) {
             for (;;) {
                 // Define quick stubs for attributes.
                 const xpc_qsPropertySpec *ps = propspecs + entry->prop_index;
                 const xpc_qsPropertySpec *ps_end = ps + entry->n_props;
                 for ( ; ps < ps_end; ++ps) {
                     definedProperty = true;
-                    if (!JS_DefineProperty(cx, proto, ps->name, JSVAL_VOID,
-                                           ps->getter, ps->setter,
+                    if (!JS_DefineProperty(cx, proto,
+                                           stringTable + ps->name_index,
+                                           JSVAL_VOID, ps->getter, ps->setter,
                                            flags | JSPROP_SHARED)) 
                         return false;
                 }
 
                 // Define quick stubs for methods.
                 const xpc_qsFunctionSpec *fs = funcspecs + entry->func_index;
                 const xpc_qsFunctionSpec *fs_end = fs + entry->n_funcs;
                 for ( ; fs < fs_end; ++fs) {
-                    if (!JS_DefineFunction(cx, proto, fs->name,
+                    if (!JS_DefineFunction(cx, proto,
+                                           stringTable + fs->name_index,
                                            reinterpret_cast<JSNative>(fs->native),
                                            fs->arity, flags))
                         return false;
                 }
 
                 // Next.
                 size_t j = entry->parentInterface;
                 if (j == XPC_QS_NULL_INDEX)
--- a/js/xpconnect/src/XPCQuickStubs.h
+++ b/js/xpconnect/src/XPCQuickStubs.h
@@ -47,29 +47,23 @@
 
 /* XPCQuickStubs.h - Support functions used only by quick stubs. */
 
 class XPCCallContext;
 
 #define XPC_QS_NULL_INDEX  ((uint16_t) -1)
 
 struct xpc_qsPropertySpec {
-    const char *name;
+    uint16_t name_index;
     JSPropertyOp getter;
     JSStrictPropertyOp setter;
 };
 
 struct xpc_qsFunctionSpec {
-    const char *name;
-    JSNative native;
-    uintN arity;
-};
-
-struct xpc_qsTraceableSpec {
-    const char *name;
+    uint16_t name_index;
     JSNative native;
     uintN arity;
 };
 
 /** A table mapping interfaces to quick stubs. */
 struct xpc_qsHashEntry {
     nsID iid;
     uint16_t prop_index;
@@ -163,17 +157,18 @@ public:
   }
 };
 
 JSBool
 xpc_qsDefineQuickStubs(JSContext *cx, JSObject *proto, uintN extraFlags,
                        PRUint32 ifacec, const nsIID **interfaces,
                        PRUint32 tableSize, const xpc_qsHashEntry *table,
                        const xpc_qsPropertySpec *propspecs,
-                       const xpc_qsFunctionSpec *funcspecs);
+                       const xpc_qsFunctionSpec *funcspecs,
+                       const char *stringTable);
 
 /** Raise an exception on @a cx and return false. */
 JSBool
 xpc_qsThrow(JSContext *cx, nsresult rv);
 
 /**
  * Fail after an XPCOM getter or setter returned rv.
  *
--- a/js/xpconnect/src/qsgen.py
+++ b/js/xpconnect/src/qsgen.py
@@ -120,18 +120,16 @@
 
 import xpidl
 import header
 import os, re
 import sys
 
 # === Preliminaries
 
-MAX_TRACEABLE_NATIVE_ARGS = 8
-
 # --makedepend-output support.
 make_dependencies = []
 make_targets = []
 
 def warn(msg):
     sys.stderr.write(msg + '\n')
 
 def unaliasType(t):
@@ -384,16 +382,48 @@ def writeHeaderFile(filename, name):
                 "  " + name + "_ClearInterfaces();\n"
                 "}\n\n"
                 "#endif\n")
     finally:
         f.close()
 
 # === Generating the source file
 
+class StringTable:
+    def __init__(self):
+        self.current_index = 0;
+        self.table = {}
+        self.reverse_table = {}
+
+    def c_strlen(self, string):
+        return len(string) + 1
+
+    def stringIndex(self, string):
+        if string in self.table:
+            return self.table[string]
+        else:
+            result = self.current_index
+            self.table[string] = result
+            self.current_index += self.c_strlen(string)
+            return result
+
+    def writeDefinition(self, f, name):
+        entries = self.table.items()
+        entries.sort(key=lambda x:x[1])
+        # Avoid null-in-string warnings with GCC and potentially
+        # overlong string constants; write everything out the long way.
+        def explodeToCharArray(string):
+            return ", ".join(map(lambda x:"'%s'" % x, string))
+        f.write("static const char %s[] = {\n" % name)
+        for (string, offset) in entries[:-1]:
+            f.write("  /* %5d */ %s, '\\0',\n"
+                    % (offset, explodeToCharArray(string)))
+        f.write("  /* %5d */ %s, '\\0' };\n\n"
+                % (entries[-1][1], explodeToCharArray(entries[-1][0])))
+
 def substitute(template, vals):
     """ Simple replacement for string.Template, which isn't in Python 2.3. """
     def replacement(match):
         return vals[match.group(1)]
     return re.sub(r'\${(\w+)}', replacement, template)
 
 # From JSData2Native.
 argumentUnboxingTemplates = {
@@ -1043,72 +1073,59 @@ def writeQuickStub(f, customMethodCalls,
 
     # Epilog.
     f.write("}\n\n")
 
     # Now write out the call to the template function.
     if customMethodCall is not None:
         f.write(callTemplate)
 
-def writeAttrStubs(f, customMethodCalls, attr):
+def writeAttrStubs(f, customMethodCalls, stringtable, attr):
     cmc = customMethodCalls.get(attr.iface.name + "_" + header.methodNativeName(attr), None)
     custom = cmc and cmc.get('skipgen', False)
 
     getterName = (attr.iface.name + '_'
                   + header.attributeNativeName(attr, True))
     if not custom:
         writeQuickStub(f, customMethodCalls, attr, getterName)
     if attr.readonly:
         setterName = 'xpc_qsGetterOnlyPropertyStub'
     else:
         setterName = (attr.iface.name + '_'
                       + header.attributeNativeName(attr, False))
         if not custom:
             writeQuickStub(f, customMethodCalls, attr, setterName, isSetter=True)
 
-    ps = ('{"%s", %s, %s}'
-          % (attr.name, getterName, setterName))
+    ps = ('{%d, %s, %s}'
+          % (stringtable.stringIndex(attr.name), getterName, setterName))
     return ps
 
-def writeMethodStub(f, customMethodCalls, method):
+def writeMethodStub(f, customMethodCalls, stringtable, method):
     """ Write a method stub to `f`. Return an xpc_qsFunctionSpec initializer. """
 
     cmc = customMethodCalls.get(method.iface.name + "_" + header.methodNativeName(method), None)
     custom = cmc and cmc.get('skipgen', False)
 
     stubName = method.iface.name + '_' + header.methodNativeName(method)
     if not custom:
         writeQuickStub(f, customMethodCalls, method, stubName)
-    fs = '{"%s", %s, %d}' % (method.name, stubName, len(method.params))
+    fs = '{%d, %s, %d}' % (stringtable.stringIndex(method.name),
+                           stubName, len(method.params))
     return fs
 
-def writeTraceableStub(f, customMethodCalls, method):
-    """ Write a method stub to `f`. Return an xpc_qsTraceableSpec initializer. """
-
-    cmc = customMethodCalls.get(method.iface.name + "_" + header.methodNativeName(method), None)
-    custom = cmc and cmc.get('skipgen', False)
-
-    stubName = method.iface.name + '_' + header.methodNativeName(method)
-    if not custom:
-        writeTraceableQuickStub(f, customMethodCalls, method, stubName)
-    fs = '{"%s", %s, %d}' % (method.name,
-                             "JS_DATA_TO_FUNC_PTR(JSNative, &%s_trcinfo)" % stubName,
-                             len(method.params))
-    return fs
-
-def writeStubsForInterface(f, customMethodCalls, iface):
+def writeStubsForInterface(f, customMethodCalls, stringtable, iface):
     f.write("// === interface %s\n\n" % iface.name)
     propspecs = []
     funcspecs = []
     for member in iface.stubMembers:
         if member.kind == 'attribute':
-            ps = writeAttrStubs(f, customMethodCalls, member)
+            ps = writeAttrStubs(f, customMethodCalls, stringtable, member)
             propspecs.append(ps)
         elif member.kind == 'method':
-            fs = writeMethodStub(f, customMethodCalls, member)
+            fs = writeMethodStub(f, customMethodCalls, stringtable, member)
             funcspecs.append(fs)
         else:
             raise TypeError('expected attribute or method, not %r'
                             % member.__class__.__name__)
 
     iface.propspecs = propspecs
     iface.funcspecs = funcspecs
 
@@ -1151,17 +1168,17 @@ def writeSpecs(f, elementType, varname, 
         if specs:
             spec_indices[iface.name] = index
             f.write("    // %s (index %d)\n" % (iface.name,index))
             for s in specs:
                 f.write("    %s,\n" % s)
             index += len(specs)
     f.write("};\n\n")
 
-def writeDefiner(f, conf, interfaces):
+def writeDefiner(f, conf, stringtable, interfaces):
     f.write("// === Definer\n\n")
 
     # Write out the properties and functions
     propspecs_indices = {}
     funcspecs_indices = {}
     prop_array_name = "all_properties"
     func_array_name = "all_functions"
     writeSpecs(f, "xpc_qsPropertySpec", prop_array_name,
@@ -1248,24 +1265,33 @@ def writeDefiner(f, conf, interfaces):
 
     f.write("static const xpc_qsHashEntry tableData[] = {\n")
     f.write(",\n".join(entries))
     f.write("\n    };\n\n")
     f.write("// Make sure our table indices aren't overflowed\n"
             "PR_STATIC_ASSERT((sizeof(tableData) / sizeof(tableData[0])) < (1 << (8 * sizeof(tableData[0].parentInterface))));\n"
             "PR_STATIC_ASSERT((sizeof(tableData) / sizeof(tableData[0])) < (1 << (8 * sizeof(tableData[0].chain))));\n\n")
 
+    # The string table for property and method names.
+    table_name = "stringtab"
+    stringtable.writeDefinition(f, table_name)
+    structNames = [prop_array_name, func_array_name]
+    for name in structNames:
+        f.write("PR_STATIC_ASSERT(sizeof(%s) < (1 << (8 * sizeof(%s[0].name_index))));\n"
+                % (table_name, name))
+    f.write("\n")
+
     # the definer function (entry point to this quick stubs file)
     f.write("JSBool %s_DefineQuickStubs(" % conf.name)
     f.write("JSContext *cx, JSObject *proto, uintN flags, PRUint32 count, "
             "const nsID **iids)\n"
             "{\n")
     f.write("    return xpc_qsDefineQuickStubs("
-            "cx, proto, flags, count, iids, %d, tableData, %s, %s);\n" % (
-            size, prop_array_name, func_array_name))
+            "cx, proto, flags, count, iids, %d, tableData, %s, %s, %s);\n" % (
+            size, prop_array_name, func_array_name, table_name))
     f.write("}\n\n\n")
 
 
 stubTopTemplate = '''\
 /* THIS FILE IS AUTOGENERATED - DO NOT EDIT */
 #include "jsapi.h"
 #include "qsWinUndefs.h"
 #include "prtypes.h"
@@ -1324,19 +1350,20 @@ def writeStubFile(filename, headerFilena
             resulttypes.extend(writeIncludesForInterface(iface))
         resulttypes.extend(conf.customReturnInterfaces)
         for customInclude in conf.customIncludes:
             f.write('#include "%s"\n' % customInclude)
         f.write("\n\n")
         writeResultXPCInterfacesArray(f, conf, frozenset(resulttypes))
         for customQS in conf.customQuickStubs:
             f.write('#include "%s"\n' % customQS)
+        stringtable = StringTable()
         for iface in interfaces:
-            writeStubsForInterface(f, conf.customMethodCalls, iface)
-        writeDefiner(f, conf, interfaces)
+            writeStubsForInterface(f, conf.customMethodCalls, stringtable, iface)
+        writeDefiner(f, conf, stringtable, interfaces)
     finally:
         f.close()
 
 def makeQuote(filename):
     return filename.replace(' ', '\\ ')  # enjoy!
 
 def writeMakeDependOutput(filename):
     print "Creating makedepend file", filename