In my previous post, I discussed the size of libxul as compiled by various versions of GCC. Due to some configuration quirks, it turns out that the comparison was flawed.
To recap: GCC versions 4.5-4.7 contained, among other things, vtables and their associated relocations for classes that were never instantiated. I theorized that some compiler optimization must have been responsible for this, and that this compiler optimization must have gotten disabled in those versions. Thinking about it afterwards, it turned out that there was a simple way to check this theory: examine the object files for the vtables. Some objects compiled by versions 4.5-4.7 must have the vtables, and no objects from versions 4.4 and 4.8 should contain the vtables. So let’s check, using nsIDOMSVGTextElement
as an example:
[froydnj@cerebro froydnj]$ for d in 4 5 6 7 8; do for o in $(find build-mozilla-gcc-4${d}/ -name '*.o'); do if readelf -sW $o |c++filt| grep -q 'vtable for nsIDOMSVGTextElement' 2>/dev/null; then echo $o; readelf -sW $o |c++filt|grep 'vtable for nsIDOMSVGTextElement' fi done done build-mozilla-gcc-44/content/svg/content/src/SVGTextElement.o 971: 0000000000000000 856 OBJECT WEAK HIDDEN 450 vtable for nsIDOMSVGTextElement build-mozilla-gcc-45/content/svg/content/src/SVGTextElement.o 1241: 0000000000000000 856 OBJECT WEAK HIDDEN 676 vtable for nsIDOMSVGTextElement build-mozilla-gcc-46/content/svg/content/src/SVGTextElement.o 1021: 0000000000000000 856 OBJECT WEAK HIDDEN 498 vtable for nsIDOMSVGTextElement build-mozilla-gcc-47/content/svg/content/src/SVGTextElement.o 1075: 0000000000000000 856 OBJECT WEAK HIDDEN 533 vtable for nsIDOMSVGTextElement build-mozilla-gcc-48/content/svg/content/src/SVGTextElement.o 831: 0000000000000000 856 OBJECT WEAK HIDDEN 532 vtable for nsIDOMSVGTextElement
So all versions of the compiler are generating the vtables that are sometimes present and sometimes not in the compiled libxul. Why do the vtables sometimes disappear?
The linker on Linux systems has a --gc-sections option that eliminates unused sections from the final output file, using a form of mark and sweep garbage collection. Normally, this is not terribly effective, since all of your program code goes into .text (resp. data into .data and so forth), and something in .text ought to be getting used. But Mozilla is compiled with the options -ffunction-sections and -fdata-sections; -ffunction-sections gives each function its own uniquely named section and -fdata-sections does a similar thing for variables. Using --gc-sections with the linker, then, effectively eliminates unused functions and/or variables that the compiler can’t prove are unused. (The compiler can eliminate unused static variables from a compilation unit, for instance, but eliminating unused variables that are visible outside of a compilation unit requires the linker’s help.) And indeed, the linking process on Linux uses this --gc-sections option.
…most of the time. Depending on the vagaries of the GCC compiler version and the version of the linker being used, using --gc-sections can impede the debugging experience. So bug 670659 added a check to disable --gc-sections if using that option altered the debugging information in unhelpful ways.
You can probably see where this is going: on my machine, GCC versions 4.5-4.7 failed this check and so the --gc-sections option was not used with those versions. (GCC 4.8 actually wound up bypassing the check altogether.) Unfortunately, compiling things so the --gc-sections option is consistently used is difficult because of how configure.in is structured.
Lesson learned: double-check your experimental setup before analyzing your results! Make sure everything’s being done consistently between your test configurations so your measurements accurately reflect differences in what you’re measuring.