Bug 711563 - flatten property and function names; r=jorendorff
authorNathan Froyd <froydnj@mozilla.com>
Thu, 29 Dec 2011 16:20:26 -0500
changeset 84558 dbb0ed6a5a6f0000b7c2280e9143097c3e812345
parent 84557 1f327a1c588b76be1b4c26a3973805511b84739a
child 84559 9cf47a611458a7e53639aee78c33450ef4ed092b
push id4933
push userphilringnalda@gmail.com
push dateMon, 16 Jan 2012 06:23:14 +0000
treeherdermozilla-inbound@9cf47a611458 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs711563
milestone12.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 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