Save state before possibly messing things up
authorBenjamin Smedberg <benjamin@smedbergs.us>
Fri, 25 Jul 2008 20:41:11 -0400
changeset 161 f18bbe915634f8cf6e8b1805d80342c53423d6b3
parent 160 fd41ae75c7983b0c8aeff594c5c4cb25cde2ce5e
child 162 3ae1ca70680d55840cbf5a60088ebaebfe2bddc5
push id37
push userbsmedberg@mozilla.com
push dateSat, 26 Jul 2008 04:16:20 +0000
Save state before possibly messing things up
comptr-rewrite.patch
comptr-rewrite.patch2
comptr-rewrite.patch5
series
static-check-gc-attributes
static-check-gc-attributes2
static-check-gc-attributes3
--- a/comptr-rewrite.patch
+++ b/comptr-rewrite.patch
@@ -1,8 +1,9 @@
+* * *
 * * *
 * * *
 * * *
 * * *
 * * *
 * * *
 * * *
 * * *
deleted file mode 100644
new file mode 100644
--- /dev/null
+++ b/comptr-rewrite.patch5
@@ -0,0 +1,38 @@
+diff --git a/xpcom/glue/nsISupportsUtils.h b/xpcom/glue/nsISupportsUtils.h
+--- a/xpcom/glue/nsISupportsUtils.h
++++ b/xpcom/glue/nsISupportsUtils.h
+@@ -85,15 +85,14 @@ public:
+         return MMgc::GCObject::operator new(size, NS_GetGC());
+     }
+ 
+-protected:
+     static void operator delete(void* obj)
+     {
+-        NS_NOTREACHED("Don't delete GCObjects!");
++        NS_GetGC()->Free(obj);
+     }
+ 
+     static void operator delete[](void* obj)
+     {
+-        NS_NOTREACHED("Don't delete GCObjects!");
++        NS_GetGC()->Free(obj);
+     }
+ };
+ 
+@@ -111,11 +110,14 @@ public:
+         return MMgc::GCFinalizedObject::operator new(size, NS_GetGC());
+     }
+ 
+-protected:
++private:
+     static void operator delete(void *obj)
+     {
+-        NS_NOTREACHED("Don't delete GCObjects!");
++        NS_GetGC()->Free(obj);
+     }
++
++    static void* operator new[](size_t size); // NOT IMPLEMENTED
++    static void operator delete[](void *obj); // NOT IMPLEMENTED
+ };
+ 
+ /**
--- a/series
+++ b/series
@@ -189,31 +189,29 @@ proxy-create-namespace
 nsHashtable-annotation
 nsSegmentedBuffer-allocator-unmanaged
 NS_FINALIZER_NOT_REQUIRED-xpcom
 nsChainedEventQueue-gcobject
 TestPageLoad-namespace
 automatic-garburator
 automatic-gcobject
 automatic-remove-addrefs
-static-check-gc-attributes2
 XPCJSContextStack-is-gcfinalizable
 nsTObserverArray-gcsafety
 nsExpirationTracker-GC-TArray
 nsJSONWriter-finalized
 nsWindow-unmanaged
 nsGUIEvents-allowonstack2
 views-unmanaged
-static-check-gc-attributes3
-comptr-rewrite.patch2
 comarray.patch2
 comptr-rewrite.patch3
 nsProtocolProxyService-FilterLink-gcobject
 TextRunExpiringCache-finalized
 nsFontCache-mContext-unmanaged
 nsJSONWriter-temp-finalizable
 nsTimeout-GCObject2
 NameSpaceDecl-mOwner-unmanaged
 comptr-rewrite.patch4
 content-xslt-gcobjects
 xultemplates-gcobjects
 xbl-gcobjects
 xul-gcobjects
+comptr-rewrite.patch5
--- a/static-check-gc-attributes
+++ b/static-check-gc-attributes
@@ -1,11 +1,13 @@
 Add static checking of gc types and correct inheritance of GCFinalizable. Storage-class analysis is getting more precise. See http://wiki.mozilla.org/XPCOMGC/Static_Checker for some readable descriptions.
 
 This doesn't yet re-implement finalizer correctness, thought it will now that we have a reasonable pretense of storage classes. Come to think of it, I should be more precise right now about non-managed classes with destructors... these need to be marked NS_GCOK
+* * *
+* * *
 
 diff --git a/config/config.mk b/config/config.mk
 --- a/config/config.mk
 +++ b/config/config.mk
 @@ -514,6 +514,7 @@ TREEHYDRA_MODULES = \
  TREEHYDRA_MODULES = \
    $(topsrcdir)/xpcom/analysis/outparams.js \
    $(topsrcdir)/xpcom/analysis/stack.js \
@@ -296,18 +298,18 @@ diff --git a/xpcom/analysis/stack.js b/x
 +        }
 +        else if (hasAttribute(fncallobj, 'NS_gcallocator')) {
 +          allocType = 'gc';
 +        }
 +        else if (hasAttribute(fncallobj, 'NS_gcfinalizedallocator')) {
 +          allocType = 'gcfinalized';
 +        }
 +        else {
-+          error("Call to un-annotated %s\n%s:   declared here".format(fncallobj.name, fncallobj.loc), getLocation(stmt));
-+          return;
++          // error("Call to un-annotated %s\n%s:   declared here".format(fncallobj.name, fncallobj.loc), getLocation(stmt));
++          allocType = 'malloc';
 +        }
 +      }
 +
 +      let m;
 +      let sc = getStorageClass(destType);
 +      switch (allocType) {
 +      case 'malloc':
 +        m = sc.blockMalloc([]);
@@ -352,34 +354,35 @@ diff --git a/xpcom/analysis/static-check
 --- a/xpcom/analysis/static-checking.js
 +++ b/xpcom/analysis/static-checking.js
 @@ -1,3 +1,5 @@
 +require({ version: '1.8' });
 +
  /**
   * A script for GCC-dehydra to analyze the Mozilla codebase and catch
   * patterns that are incorrect, but which cannot be detected by a compiler. */
-@@ -10,6 +12,65 @@ function treehydra_enabled() {
+@@ -9,6 +11,65 @@ function treehydra_enabled() {
+ function treehydra_enabled() {
    return this.hasOwnProperty('TREE_CODE');
  }
- 
++
 +String.prototype.format = function string_format() {
 +  // there are two modes of operation... unnamed indices are read in order;
 +  // named indices using %(name)s. The two styles cannot be mixed.
 +  // Unnamed indices can be passed as either a single argument to this function,
 +  // multiple arguments to this function, or as a single array argument
 +  let curindex = 0;
 +  let d;
-+  
++
 +  if (arguments.length > 1) {
 +    d = arguments;
 +  }
 +  else
 +    d = arguments[0];
-+  
++
 +  function r(s, key, type) {
 +    let v;
 +    if (key == "") {
 +      if (curindex == -1)
 +        throw Error("Cannot mix named and positional indices in string formatting.");
 +
 +      if (curindex == 0 && (!(d instanceof Object) || !(0 in d))) {
 +        v = d;
@@ -392,17 +395,17 @@ diff --git a/xpcom/analysis/static-check
 +
 +      ++curindex;
 +    }
 +    else {
 +      key = key.slice(1, -1);
 +      if (curindex > 0)
 +        throw Error("Cannot mix named and positional indices in string formatting.");
 +      curindex = -1;
-+      
++
 +      if (!(key in d))
 +        throw Error("Key '%s' not present during string substitution.".format(key));
 +      v = d[key];
 +    }
 +    switch (type) {
 +    case "s":
 +      return v.toString();
 +    case "r":
@@ -414,91 +417,86 @@ diff --git a/xpcom/analysis/static-check
 +    case "%":
 +      return "%";
 +    default:
 +      throw Error("Unexpected format character '%s'.".format(type));
 +    }
 +  }
 +  return this.replace(/%(\([^)]+\))?(.)/g, r);
 +};
-+               
+ 
  include('unstable/getopt.js');
  [options, args] = getopt();
- 
 @@ -43,19 +104,26 @@ function process_type(c)
        module.process_type(c);
  }
  
+-function hasAttribute(c, attrname)
 +function hasAnyAttribute(c, attrlist)
-+{
-+  if (c.attributes === undefined)
-+    return false;
-+  
+ {
+-  var attr;
+-
+   if (c.attributes === undefined)
+     return false;
+ 
+-  for each (attr in c.attributes)
+-    if (attr.name == 'user' && attr.value[0] == attrname)
+-      return true;
 +  for each (let attr in c.attributes) {
 +    if (attr.name == 'user' && attrlist.some(function(v) {
 +      return v == attr.value[0];
 +    }))
 +      return attr.value[0];
 +  }
-+  
-+  return false;
-+}
+ 
+   return false;
+ }
 +
- function hasAttribute(c, attrname)
- {
--  var attr;
++function hasAttribute(c, attrname)
++{
 +  return hasAnyAttribute(c, [attrname]) != false;
 +}
- 
--  if (c.attributes === undefined)
--    return false;
--
--  for each (attr in c.attributes)
--    if (attr.name == 'user' && attr.value[0] == attrname)
--      return true;
--
--  return false;
--}
++
  function process_function(f, stmts)
  {
    for each (let module in modules)
-@@ -83,3 +151,384 @@ function input_end()
+@@ -83,3 +151,402 @@ function input_end()
      if (module.hasOwnProperty('input_end'))
        module.input_end();
  }
 +
 +function StorageReason(loc, message, prev)
 +{
 +  this.loc = loc;
 +  this.message = message;
 +  this.prev = prev;
 +}
 +StorageReason.prototype.toString = function()
 +{
 +  let loc = this.loc;
 +  if (loc === undefined)
 +    loc = "<unknown location>";
-+  
++
 +  let str = "%s:   %s".format(loc, this.message);
 +  if (this.prev)
 +    str += "\n%s".format(this.prev);
 +  return str;
 +};
 +
 +/**
 + * The various Storage types have a common interface:
 + * blockStack(stack)
 + * blockGlobal(stack)
 + * blockMalloc(stack)
 + * blockGC(stack)
 + * safeFinalizer(stack)
 + * canSkipFinalization(stack)
-+ * 
++ *
 + * Each of these returns null if everything's ok, or a StorageReason
-+ * 
++ *
 + * Any sub-types are checked against the type stack to ensure we don't enter
 + * an iloop checking pointer classes.
 + */
 +function checkstack(stack, i)
 +{
 +  return stack.some(function(si) si === i);
 +}
 +
@@ -525,17 +523,17 @@ diff --git a/xpcom/analysis/static-check
 +    let subtypeClass = getStorageClass(this._type.type, stack);
 +    if (!subtypeClass.blockGC(stack)) {
 +      let reason = subtypeClass.blockMalloc(stack);
 +      if (reason)
 +        return new StorageReason(this._type.type.loc, "pointer to", reason);
 +    }
 +    return null;
 +  },
-+  
++
 +  blockStack: function() { return null; },
 +  blockGlobal: function(stack) { return this.blockNotManaged(stack); },
 +  blockMalloc: function(stack) { return this.blockNotManaged(stack); },
 +  blockGC: function() { return null; },
 +  safeFinalizer: function() { return null; },
 +  canSkipFinalization: function() { return null; },
 +  toString: function() { return "PointerStorageClass(%s)".format(this._type); }
 +};
@@ -575,45 +573,45 @@ diff --git a/xpcom/analysis/static-check
 +{
 +  this._type = type;
 +}
 +TypedefStorageClass.prototype = {
 +  _forward: function(fname, stack) {
 +    stack = stack.concat(this._type);
 +    return getStorageClass(this._type.typedef)[fname](stack);
 +  },
-+  
++
 +  blockStack: function(stack) {
 +    let m = hasAnyAttribute(this._type, ["NS_GC"]);
 +    if (m != false)
 +      return new StorageReason(this._type.loc, "typedef %s marked with annotation %s".format(this._type.name, m));
 +    return this._forward('blockStack', stack);
 +  },
-+  
++
 +  blockGlobal: function(stack) {
 +    let m = hasAnyAttribute(this._type, ["NS_stack", "NS_managed", "NS_GC"]);
 +    if (m != false)
 +      return new StorageReason(this._type.loc, "typedef %s marked with annotation %s".format(this._type.name, m));
 +    return this._forward('blockGlobal', stack);
 +  },
-+  
++
 +  blockMalloc: function(stack) {
 +    let m = hasAnyAttribute(this._type, ["NS_stack", "NS_managed", "NS_GC"]);
 +    if (m != false)
 +      return new StorageReason(this._type.loc, "typedef %s marked with annotation %s".format(this._type.name, m));
 +    return this._forward('blockMalloc', stack);
 +  },
-+  
++
 +  blockGC: function(stack) {
 +    let m = hasAnyAttribute(this._type, ["NS_stack", "NS_NoGC"]);
 +    if (m != false)
 +      return new StorageReason(this._type.loc, "typedef %s marked with annotation %s".format(this._type.name, m));
 +    return this._forward('blockGC', stack);
 +  },
-+  
++
 +  safeFinalizer: function(stack) {
 +    return this._forward('safeFinalizer', stack);
 +  },
 +  canSkipFinalization: function(stack) {
 +    return this._forward('canSkipFinalization', stack);
 +  },
 +  toString: function() { return "TypedefStorageClass(%s)".format(this._type); }
 +};
@@ -622,17 +620,17 @@ diff --git a/xpcom/analysis/static-check
 + * Does a class have a declared destructor?
 + */
 +function hasOwnDestructor(c)
 +{
 +  for each (let member in c.members) {
 +    // dehydra version
 +    if (member.isFunction && /::~/(member.name))
 +      return true;
-+    
++
 +    // treehydra version
 +    if (member.isDestructor &&
 +        !DECL_ARTIFICIAL(member._type))
 +      return true;
 +  }
 +
 +  return false;
 +}
@@ -644,122 +642,140 @@ diff --git a/xpcom/analysis/static-check
 +StructStorageClass.prototype = {
 +  /**
 +   * @returns false or a StorageReason
 +   * @note This function does not recurse, it's only for local use
 +   */
 +  isManaged: function() {
 +    let m = hasAnyAttribute(this._type, ["NS_GC", "NS_managed"]);
 +    if (m != false)
-+      return new StorageReason(this._type.loc, "Class %s is annotated %s".format(this._type.name, m));
-+    
++      return new StorageReason(this._type.loc, "%s %s is annotated %s".format(this._type.kind, this._type.name, m));
++
 +    if (this._type.name == 'MMgc::GCObject' ||
 +        this._type.name == 'MMgc::GCFinalizable' ||
 +        this._type.name == 'XPCOMGCObject' ||
 +        this._type.name == 'XPCOMGCFinalizedObject')
-+      return new StorageReason(this._type.loc, "Class %s is considered managed.".format(this._type.name));
-+    
++      return new StorageReason(this._type.loc, "%s %s is considered managed.".format(this._type.kind, this._type.name));
++
 +    return null;
 +  },
-+  
++
 +  iterItems: function(fname, stack) {
 +    if (this._type.isIncomplete)
 +      return null;
 +
 +    stack = stack.concat(this._type);
 +
 +    for each (let base in this._type.bases) {
 +      let r = getStorageClass(base)[fname](stack);
 +      if (r != null)
-+        return new StorageReason(this._type.loc, "class %s is a base of %s".format([base.name, this._type.name]), r);
++        return new StorageReason(this._type.loc, "%s %s is a base of %s %s".format(base.kind, base.name, this._type.kind, this._type.name), r);
 +    }
 +    for each (let member in this._type.members) {
 +      if (member.isFunction || member.isStatic)
 +        continue;
-+      
++
 +      let r = getStorageClass(member)[fname](stack);
 +      if (r != null)
-+        return new StorageReason(member.loc, "due to member %s".format(member.name), r);
++        return new StorageReason(this._type.loc, "in %s %s".format(this._type.kind, this._type.name),
++          new StorageReason(member.loc,
++                            "member %s".format(member.name, member.type), r));
 +    }
 +    return null;
 +  },
 +
 +  blockStack: function(stack) {
 +    let m = hasAnyAttribute(this._type, ["NS_GC"]);
 +    if (m != false)
 +      return new StorageReason(this._type.loc, "%s %s marked as %s".format(this._type.kind, this._type.name, m));
 +    return this.iterItems('blockStack', stack);
 +  },
-+  
++
 +  blockGlobal: function(stack) {
 +    let m = hasAnyAttribute(this._type, ["NS_stack"]);
 +    if (m != false)
 +      return new StorageReason(this._type.loc, "%s %s marked as %s".format(this._type.kind, this._type.name, m));
 +
 +    m = this.isManaged();
 +    if (m != null)
 +      return m;
 +
 +    return this.iterItems('blockGlobal', stack);
 +  },
-+  
++
 +  blockMalloc: function(stack) {
 +    let m = hasAnyAttribute(this._type, ["NS_stack"]);
 +    if (m != false) {
 +      return new StorageReason(this._type.loc, "%s %s marked as %s".format(this._type.kind, this._type.name, m));
 +    }
-+    
++
 +    m = this.isManaged();
 +    if (m != null)
 +      return m;
-+    
++
 +    return this.iterItems('blockMalloc', stack);
 +  },
-+  
++
 +  blockGC: function(stack) {
 +    let m = hasAnyAttribute(this._type, ["NS_NoGC"]);
 +    if (m != false)
 +      return new StorageReason(this._type.loc, "%s %s marked as %s".format(this._type.kind, this._type.name, m));
-+    
++
 +    return this.iterItems('blockGC', stack);
 +  },
-+  
++
 +  safeFinalizer: function(stack) {
 +    let m = this.iterItems('safeFinalizer', stack);
 +    if (m != null)
 +      return m;
 +
 +    m = hasAnyAttribute(this._type, ["NS_GCOK"]);
 +    if (m != false)
 +      return null;
 +
 +    m = this.isManaged();
 +    if (m != null)
 +      return null; // Managed classes are finalizer-safe
 +
 +    if (hasOwnDestructor(this._type))
 +      return new StorageReason(this._type.loc, "%s %s not annotated for as GC and has a destructor.".format(this._type.kind, this._type.name));
-+    
++
 +    // If this class doesn't have a destructor, it's finalizer-safe.
 +    // Implicit destructors are dealt with above in iterItems
 +    return null;
 +  },
-+  
++
 +  canSkipFinalization: function(stack) {
 +    let m = this.iterItems('canSkipFinalization', stack);
 +    if (m != null)
 +      return m;
-+    
++
 +    if (hasAttribute(this._type, 'NS_finalizer_not_required'))
 +      return null;
 +
 +    if (this._type.name == 'MMgc::GCObject' ||
++        this._type.name == 'MMgc::GCFinalizable' ||
 +        this._type.name == 'XPCOMGCObject')
 +      return null;
-+    
++
++    if (this._type.template &&
++        this._type.template.name == 'nsTArray_base' &&
++        this._type.template.arguments[0].name == 'GCAllocator')
++      return null;
++
++    if (this._type.template &&
++        this._type.template.name == 'nsTArray' &&
++        this._type.template.arguments[1].name == 'GCAllocator')
++      return null;
++
++    if (this._type.template &&
++	this._type.template.name == 'nsVoidArrayBase' &&
++	this._type.template.arguments[0].name == 'GCAllocator')
++      return null;
++
 +    if (hasOwnDestructor(this._type))
 +      return new StorageReason(this._type.loc, "%s %s has a destructor and is not annotated NS_FINALIZER_NOT_REQUIRED.".format(this._type.kind, this._type.name));
 +
 +    return null;
 +  },
 +  toString: function() { return "StructStorageClass(%s)".format(this._type); }
 +};
 +
@@ -769,23 +785,23 @@ diff --git a/xpcom/analysis/static-check
 +}
 +DeclStorageClass.prototype = {
 +  blockStack: function(stack) {
 +    return getStorageClass(this._decl.type).blockStack(stack);
 +  },
 +  blockGlobal: function(stack) {
 +    if (hasAttribute(this._decl, "NS_unmanaged"))
 +      return null;
-+    
++
 +    return getStorageClass(this._decl.type).blockGlobal(stack);
 +  },
 +  blockMalloc: function(stack) {
 +    if (hasAttribute(this._decl, "NS_unmanaged"))
 +      return null;
-+    
++
 +    return getStorageClass(this._decl.type).blockMalloc(stack);
 +  },
 +  blockGC: function(stack) {
 +    return getStorageClass(this._decl.type).blockGC(stack);
 +  },
 +  safeFinalizer: function(stack) {
 +    return getStorageClass(this._decl.type).safeFinalizer(stack);
 +  },
@@ -797,23 +813,23 @@ diff --git a/xpcom/analysis/static-check
 +
 +/**
 + * Get the storage class for a type.
 + */
 +function getStorageClass(type)
 +{
 +  if (type.typedef)
 +    return new TypedefStorageClass(type);
-+  
++
 +  if (type.isPointer || type.isReference)
 +    return new PointerStorageClass(type);
-+  
++
 +  if (type.isArray)
 +    return new ArrayStorageClass(type);
-+  
++
 +  if (type.isFunction)
 +    throw Error("How did a function decl end up in getStorageClass?");
 +
 +  if (type.kind) {
 +    switch (type.kind) {
 +    case "struct":
 +    case "class":
 +      return new StructStorageClass(type);
@@ -821,26 +837,26 @@ diff --git a/xpcom/analysis/static-check
 +      // TODO: what the hell should union rules be? For now, bail!
 +      return ValueStorageClass;
 +    case "enum":
 +      return ValueStorageClass;
 +    default:
 +      throw Error("Unrecognized type.kind '%s'".format(type.kind));
 +    }
 +  }
-+  
++
 +  if (type.parameters) {
 +    // this is a function *type*... we can end up here via function pointers
 +    return ValueStorageClass;
 +  }
 +
 +  if (type.precision || type.name == 'void') {
 +    if (type.type)
 +      throw Error("I thought this was a numeric type, but apparently it's not: %s".format(type));
-+    
++
 +    return ValueStorageClass;
 +  }
 +
 +  // If we're here, whatever we have is probably a decl...
 +  if (type.type === undefined)
 +    throw Error("Analysis error: %s should be a decl but doesn't have a type".format(type));
 +
 +  return new DeclStorageClass(type);
deleted file mode 100644
--- a/static-check-gc-attributes2
+++ /dev/null
@@ -1,80 +0,0 @@
-diff --git a/xpcom/analysis/stack.js b/xpcom/analysis/stack.js
---- a/xpcom/analysis/stack.js
-+++ b/xpcom/analysis/stack.js
-@@ -118,8 +118,8 @@ function process_tree(fndecl)
-           allocType = 'gcfinalized';
-         }
-         else {
--          error("Call to un-annotated %s\n%s:   declared here".format(fncallobj.name, fncallobj.loc), getLocation(stmt));
--          return;
-+          // error("Call to un-annotated %s\n%s:   declared here".format(fncallobj.name, fncallobj.loc), getLocation(stmt));
-+          allocType = 'malloc';
-         }
-       }
- 
-diff --git a/xpcom/analysis/static-checking.js b/xpcom/analysis/static-checking.js
---- a/xpcom/analysis/static-checking.js
-+++ b/xpcom/analysis/static-checking.js
-@@ -336,14 +336,14 @@ StructStorageClass.prototype = {
-   isManaged: function() {
-     let m = hasAnyAttribute(this._type, ["NS_GC", "NS_managed"]);
-     if (m != false)
--      return new StorageReason(this._type.loc, "Class %s is annotated %s".format(this._type.name, m));
-+      return new StorageReason(this._type.loc, "%s %s is annotated %s".format(this._type.kind, this._type.name, m));
-     
-     if (this._type.name == 'MMgc::GCObject' ||
-         this._type.name == 'MMgc::GCFinalizable' ||
-         this._type.name == 'XPCOMGCObject' ||
-         this._type.name == 'XPCOMGCFinalizedObject')
--      return new StorageReason(this._type.loc, "Class %s is considered managed.".format(this._type.name));
--    
-+      return new StorageReason(this._type.loc, "%s %s is considered managed.".format(this._type.kind, this._type.name));
-+
-     return null;
-   },
-   
-@@ -356,7 +356,7 @@ StructStorageClass.prototype = {
-     for each (let base in this._type.bases) {
-       let r = getStorageClass(base)[fname](stack);
-       if (r != null)
--        return new StorageReason(this._type.loc, "class %s is a base of %s".format([base.name, this._type.name]), r);
-+        return new StorageReason(this._type.loc, "%s %s is a base of %s %s".format(base.kind, base.name, this._type.kind, this._type.name), r);
-     }
-     for each (let member in this._type.members) {
-       if (member.isFunction || member.isStatic)
-@@ -364,7 +364,9 @@ StructStorageClass.prototype = {
-       
-       let r = getStorageClass(member)[fname](stack);
-       if (r != null)
--        return new StorageReason(member.loc, "due to member %s".format(member.name), r);
-+        return new StorageReason(this._type.loc, "in %s %s".format(this._type.kind, this._type.name),
-+          new StorageReason(member.loc,
-+                            "member %s".format(member.name, member.type), r));
-     }
-     return null;
-   },
-@@ -439,9 +441,24 @@ StructStorageClass.prototype = {
-       return null;
- 
-     if (this._type.name == 'MMgc::GCObject' ||
-+        this._type.name == 'MMgc::GCFinalizable' ||
-         this._type.name == 'XPCOMGCObject')
-       return null;
-+
-+    if (this._type.template &&
-+        this._type.template.name == 'nsTArray_base' &&
-+        this._type.template.arguments[0].name == 'GCAllocator')
-+      return null;
-     
-+    if (this._type.template &&
-+        this._type.template.name == 'nsTArray' &&
-+        this._type.template.arguments[1].name == 'GCAllocator')
-+      return null;
-+    
-+    print("Checking for destructor: %s");
-+    if (this._type.template)
-+      print("template.name: %s".format(this._type.template.name));
-+
-     if (hasOwnDestructor(this._type))
-       return new StorageReason(this._type.loc, "%s %s has a destructor and is not annotated NS_FINALIZER_NOT_REQUIRED.".format(this._type.kind, this._type.name));
- 
deleted file mode 100644
--- a/static-check-gc-attributes3
+++ /dev/null
@@ -1,299 +0,0 @@
-diff --git a/xpcom/analysis/static-checking.js b/xpcom/analysis/static-checking.js
---- a/xpcom/analysis/static-checking.js
-+++ b/xpcom/analysis/static-checking.js
-@@ -19,13 +19,13 @@ String.prototype.format = function strin
-   // multiple arguments to this function, or as a single array argument
-   let curindex = 0;
-   let d;
--  
-+
-   if (arguments.length > 1) {
-     d = arguments;
-   }
-   else
-     d = arguments[0];
--  
-+
-   function r(s, key, type) {
-     let v;
-     if (key == "") {
-@@ -48,7 +48,7 @@ String.prototype.format = function strin
-       if (curindex > 0)
-         throw Error("Cannot mix named and positional indices in string formatting.");
-       curindex = -1;
--      
-+
-       if (!(key in d))
-         throw Error("Key '%s' not present during string substitution.".format(key));
-       v = d[key];
-@@ -70,7 +70,7 @@ String.prototype.format = function strin
-   }
-   return this.replace(/%(\([^)]+\))?(.)/g, r);
- };
--               
-+
- include('unstable/getopt.js');
- [options, args] = getopt();
- 
-@@ -108,14 +108,14 @@ function hasAnyAttribute(c, attrlist)
- {
-   if (c.attributes === undefined)
-     return false;
--  
-+
-   for each (let attr in c.attributes) {
-     if (attr.name == 'user' && attrlist.some(function(v) {
-       return v == attr.value[0];
-     }))
-       return attr.value[0];
-   }
--  
-+
-   return false;
- }
- 
-@@ -163,7 +163,7 @@ StorageReason.prototype.toString = funct
-   let loc = this.loc;
-   if (loc === undefined)
-     loc = "<unknown location>";
--  
-+
-   let str = "%s:   %s".format(loc, this.message);
-   if (this.prev)
-     str += "\n%s".format(this.prev);
-@@ -178,9 +178,9 @@ StorageReason.prototype.toString = funct
-  * blockGC(stack)
-  * safeFinalizer(stack)
-  * canSkipFinalization(stack)
-- * 
-+ *
-  * Each of these returns null if everything's ok, or a StorageReason
-- * 
-+ *
-  * Any sub-types are checked against the type stack to ensure we don't enter
-  * an iloop checking pointer classes.
-  */
-@@ -217,7 +217,7 @@ PointerStorageClass.prototype = {
-     }
-     return null;
-   },
--  
-+
-   blockStack: function() { return null; },
-   blockGlobal: function(stack) { return this.blockNotManaged(stack); },
-   blockMalloc: function(stack) { return this.blockNotManaged(stack); },
-@@ -267,35 +267,35 @@ TypedefStorageClass.prototype = {
-     stack = stack.concat(this._type);
-     return getStorageClass(this._type.typedef)[fname](stack);
-   },
--  
-+
-   blockStack: function(stack) {
-     let m = hasAnyAttribute(this._type, ["NS_GC"]);
-     if (m != false)
-       return new StorageReason(this._type.loc, "typedef %s marked with annotation %s".format(this._type.name, m));
-     return this._forward('blockStack', stack);
-   },
--  
-+
-   blockGlobal: function(stack) {
-     let m = hasAnyAttribute(this._type, ["NS_stack", "NS_managed", "NS_GC"]);
-     if (m != false)
-       return new StorageReason(this._type.loc, "typedef %s marked with annotation %s".format(this._type.name, m));
-     return this._forward('blockGlobal', stack);
-   },
--  
-+
-   blockMalloc: function(stack) {
-     let m = hasAnyAttribute(this._type, ["NS_stack", "NS_managed", "NS_GC"]);
-     if (m != false)
-       return new StorageReason(this._type.loc, "typedef %s marked with annotation %s".format(this._type.name, m));
-     return this._forward('blockMalloc', stack);
-   },
--  
-+
-   blockGC: function(stack) {
-     let m = hasAnyAttribute(this._type, ["NS_stack", "NS_NoGC"]);
-     if (m != false)
-       return new StorageReason(this._type.loc, "typedef %s marked with annotation %s".format(this._type.name, m));
-     return this._forward('blockGC', stack);
-   },
--  
-+
-   safeFinalizer: function(stack) {
-     return this._forward('safeFinalizer', stack);
-   },
-@@ -314,7 +314,7 @@ function hasOwnDestructor(c)
-     // dehydra version
-     if (member.isFunction && /::~/(member.name))
-       return true;
--    
-+
-     // treehydra version
-     if (member.isDestructor &&
-         !DECL_ARTIFICIAL(member._type))
-@@ -337,7 +337,7 @@ StructStorageClass.prototype = {
-     let m = hasAnyAttribute(this._type, ["NS_GC", "NS_managed"]);
-     if (m != false)
-       return new StorageReason(this._type.loc, "%s %s is annotated %s".format(this._type.kind, this._type.name, m));
--    
-+
-     if (this._type.name == 'MMgc::GCObject' ||
-         this._type.name == 'MMgc::GCFinalizable' ||
-         this._type.name == 'XPCOMGCObject' ||
-@@ -346,7 +346,7 @@ StructStorageClass.prototype = {
- 
-     return null;
-   },
--  
-+
-   iterItems: function(fname, stack) {
-     if (this._type.isIncomplete)
-       return null;
-@@ -361,7 +361,7 @@ StructStorageClass.prototype = {
-     for each (let member in this._type.members) {
-       if (member.isFunction || member.isStatic)
-         continue;
--      
-+
-       let r = getStorageClass(member)[fname](stack);
-       if (r != null)
-         return new StorageReason(this._type.loc, "in %s %s".format(this._type.kind, this._type.name),
-@@ -377,7 +377,7 @@ StructStorageClass.prototype = {
-       return new StorageReason(this._type.loc, "%s %s marked as %s".format(this._type.kind, this._type.name, m));
-     return this.iterItems('blockStack', stack);
-   },
--  
-+
-   blockGlobal: function(stack) {
-     let m = hasAnyAttribute(this._type, ["NS_stack"]);
-     if (m != false)
-@@ -389,28 +389,28 @@ StructStorageClass.prototype = {
- 
-     return this.iterItems('blockGlobal', stack);
-   },
--  
-+
-   blockMalloc: function(stack) {
-     let m = hasAnyAttribute(this._type, ["NS_stack"]);
-     if (m != false) {
-       return new StorageReason(this._type.loc, "%s %s marked as %s".format(this._type.kind, this._type.name, m));
-     }
--    
-+
-     m = this.isManaged();
-     if (m != null)
-       return m;
--    
-+
-     return this.iterItems('blockMalloc', stack);
-   },
--  
-+
-   blockGC: function(stack) {
-     let m = hasAnyAttribute(this._type, ["NS_NoGC"]);
-     if (m != false)
-       return new StorageReason(this._type.loc, "%s %s marked as %s".format(this._type.kind, this._type.name, m));
--    
-+
-     return this.iterItems('blockGC', stack);
-   },
--  
-+
-   safeFinalizer: function(stack) {
-     let m = this.iterItems('safeFinalizer', stack);
-     if (m != null)
-@@ -426,17 +426,17 @@ StructStorageClass.prototype = {
- 
-     if (hasOwnDestructor(this._type))
-       return new StorageReason(this._type.loc, "%s %s not annotated for as GC and has a destructor.".format(this._type.kind, this._type.name));
--    
-+
-     // If this class doesn't have a destructor, it's finalizer-safe.
-     // Implicit destructors are dealt with above in iterItems
-     return null;
-   },
--  
-+
-   canSkipFinalization: function(stack) {
-     let m = this.iterItems('canSkipFinalization', stack);
-     if (m != null)
-       return m;
--    
-+
-     if (hasAttribute(this._type, 'NS_finalizer_not_required'))
-       return null;
- 
-@@ -449,15 +449,16 @@ StructStorageClass.prototype = {
-         this._type.template.name == 'nsTArray_base' &&
-         this._type.template.arguments[0].name == 'GCAllocator')
-       return null;
--    
-+
-     if (this._type.template &&
-         this._type.template.name == 'nsTArray' &&
-         this._type.template.arguments[1].name == 'GCAllocator')
-       return null;
--    
--    print("Checking for destructor: %s");
--    if (this._type.template)
--      print("template.name: %s".format(this._type.template.name));
-+
-+    if (this._type.template &&
-+	this._type.template.name == 'nsVoidArrayBase' &&
-+	this._type.template.arguments[0].name == 'GCAllocator')
-+      return null;
- 
-     if (hasOwnDestructor(this._type))
-       return new StorageReason(this._type.loc, "%s %s has a destructor and is not annotated NS_FINALIZER_NOT_REQUIRED.".format(this._type.kind, this._type.name));
-@@ -478,13 +479,13 @@ DeclStorageClass.prototype = {
-   blockGlobal: function(stack) {
-     if (hasAttribute(this._decl, "NS_unmanaged"))
-       return null;
--    
-+
-     return getStorageClass(this._decl.type).blockGlobal(stack);
-   },
-   blockMalloc: function(stack) {
-     if (hasAttribute(this._decl, "NS_unmanaged"))
-       return null;
--    
-+
-     return getStorageClass(this._decl.type).blockMalloc(stack);
-   },
-   blockGC: function(stack) {
-@@ -506,13 +507,13 @@ function getStorageClass(type)
- {
-   if (type.typedef)
-     return new TypedefStorageClass(type);
--  
-+
-   if (type.isPointer || type.isReference)
-     return new PointerStorageClass(type);
--  
-+
-   if (type.isArray)
-     return new ArrayStorageClass(type);
--  
-+
-   if (type.isFunction)
-     throw Error("How did a function decl end up in getStorageClass?");
- 
-@@ -530,7 +531,7 @@ function getStorageClass(type)
-       throw Error("Unrecognized type.kind '%s'".format(type.kind));
-     }
-   }
--  
-+
-   if (type.parameters) {
-     // this is a function *type*... we can end up here via function pointers
-     return ValueStorageClass;
-@@ -539,7 +540,7 @@ function getStorageClass(type)
-   if (type.precision || type.name == 'void') {
-     if (type.type)
-       throw Error("I thought this was a numeric type, but apparently it's not: %s".format(type));
--    
-+
-     return ValueStorageClass;
-   }
-