Bug 661984: Add [nostdcall] as an extended idl attribute. r=bsmedberg
authorJonas Sicking <jonas@sicking.cc>
Thu, 23 Jun 2011 19:17:58 -0700
changeset 72126 cfea84e7fd7c852e4b1b09b10eed0dded95e7bfd
parent 72125 c8f01a0d54822877edac39b04392c64d2e2c977d
child 72127 3fa43a74a6d9b593811617b04bd80666d60ddf2a
push id159
push usereakhgari@mozilla.com
push dateTue, 16 Aug 2011 17:53:11 +0000
treeherdermozilla-beta@8786e3e49240 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs661984
milestone7.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 661984: Add [nostdcall] as an extended idl attribute. r=bsmedberg
xpcom/idl-parser/header.py
xpcom/idl-parser/xpidl.py
xpcom/typelib/xpidl/xpidl_header.c
xpcom/typelib/xpidl/xpidl_util.c
--- a/xpcom/idl-parser/header.py
+++ b/xpcom/idl-parser/header.py
@@ -57,33 +57,46 @@ def firstCap(str):
 
 def attributeParamName(a):
     return "a" + firstCap(a.name)
 
 def attributeNativeName(a, getter):
     binaryname = a.binaryname is not None and a.binaryname or firstCap(a.name)
     return "%s%s" % (getter and 'Get' or 'Set', binaryname)
 
+def attributeReturnType(a, macro):
+    """macro should be NS_IMETHOD or NS_IMETHODIMP"""
+    if (a.nostdcall):
+        return macro == "NS_IMETHOD" and "virtual nsresult" or "nsresult"
+    else:
+        return macro
+
 def attributeParamlist(a, getter):
     return "%s%s" % (a.realtype.nativeType(getter and 'out' or 'in'),
                      attributeParamName(a))
 
 def attributeAsNative(a, getter):
         scriptable = a.isScriptable() and "NS_SCRIPTABLE " or ""
         params = {'scriptable': scriptable,
+                  'returntype': attributeReturnType(a, 'NS_IMETHOD'),
                   'binaryname': attributeNativeName(a, getter),
                   'paramlist': attributeParamlist(a, getter)}
-        return "%(scriptable)sNS_IMETHOD %(binaryname)s(%(paramlist)s)" % params
+        return "%(scriptable)s%(returntype)s %(binaryname)s(%(paramlist)s)" % params
 
 def methodNativeName(m):
     return m.binaryname is not None and m.binaryname or firstCap(m.name)
 
 def methodReturnType(m, macro):
     """macro should be NS_IMETHOD or NS_IMETHODIMP"""
-    if m.notxpcom:
+    if m.nostdcall and m.notxpcom:
+        return "%s%s" % (macro == "NS_IMETHOD" and "virtual " or "",
+                         m.realtype.nativeType('in').strip())
+    elif m.nostdcall:
+        return "%snsresult" % (macro == "NS_IMETHOD" and "virtual " or "")
+    elif m.notxpcom:
         return "%s_(%s)" % (macro, m.realtype.nativeType('in').strip())
     else:
         return macro
 
 def methodAsNative(m):
     scriptable = m.isScriptable() and "NS_SCRIPTABLE " or ""
 
     return "%s%s %s(%s)" % (scriptable,
@@ -405,22 +418,22 @@ def write_interface(iface, fd):
 
     fd.write(iface_template_prolog % names)
 
     for member in iface.members:
         if isinstance(member, xpidl.ConstMember) or isinstance(member, xpidl.CDATA): continue
         fd.write("/* %s */\n" % member.toIDL())
         if isinstance(member, xpidl.Attribute):
             fd.write(example_tmpl % {'implclass': implclass,
-                                     'returntype': 'NS_IMETHODIMP',
+                                     'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
                                      'nativeName': attributeNativeName(member, True),
                                      'paramList': attributeParamlist(member, True)})
             if not member.readonly:
                 fd.write(example_tmpl % {'implclass': implclass,
-                                         'returntype': 'NS_IMETHODIMP',
+                                         'returntype': attributeReturnType(member, 'NS_IMETHODIMP'),
                                          'nativeName': attributeNativeName(member, False),
                                          'paramList': attributeParamlist(member, False)})
         elif isinstance(member, xpidl.Method):
             fd.write(example_tmpl % {'implclass': implclass,
                                      'returntype': methodReturnType(member, 'NS_IMETHODIMP'),
                                      'nativeName': methodNativeName(member),
                                      'paramList': paramlistAsNative(member.params, member.realtype, notxpcom=member.notxpcom, empty='')})
         fd.write('\n')
--- a/xpcom/idl-parser/xpidl.py
+++ b/xpcom/idl-parser/xpidl.py
@@ -643,16 +643,17 @@ class ConstMember(object):
         return "\tconst %s %s = %s\n" % (self.type, self.name, self.getValue())
 
 class Attribute(object):
     kind = 'attribute'
     noscript = False
     notxpcom = False
     readonly = False
     implicit_jscontext = False
+    nostdcall = False
     binaryname = None
     null = None
     undefined = None
 
     def __init__(self, type, name, attlist, readonly, location, doccomments):
         self.type = type
         self.name = name
         self.attlist = attlist
@@ -694,18 +695,20 @@ class Attribute(object):
                     raise IDLError("Unexpected attribute value", aloc)
 
                 if name == 'noscript':
                     self.noscript = True
                 elif name == 'notxpcom':
                     self.notxpcom = True
                 elif name == 'implicit_jscontext':
                     self.implicit_jscontext = True
+                elif name == 'nostdcall':
+                    self.nostdcall = True
                 else:
-                    raise IDLError("Unexpected attribute '%s'", aloc)
+                    raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
     def resolve(self, iface):
         self.iface = iface
         self.realtype = iface.idl.getName(self.type, self.location)
         if (self.null is not None and
             getBuiltinOrNativeTypeName(self.realtype) != '[domstring]'):
             raise IDLError("'Null' attribute can only be used on DOMString",
                            self.location)
@@ -728,16 +731,17 @@ class Attribute(object):
                                           self.type, self.name)
 
 class Method(object):
     kind = 'method'
     noscript = False
     notxpcom = False
     binaryname = None
     implicit_jscontext = False
+    nostdcall = False
     optional_argc = False
 
     def __init__(self, type, name, attlist, paramlist, location, doccomments, raises):
         self.type = type
         self.name = name
         self.attlist = attlist
         self.params = paramlist
         self.location = location
@@ -759,18 +763,20 @@ class Method(object):
             if name == 'noscript':
                 self.noscript = True
             elif name == 'notxpcom':
                 self.notxpcom = True
             elif name == 'implicit_jscontext':
                 self.implicit_jscontext = True
             elif name == 'optional_argc':
                 self.optional_argc = True
+            elif name == 'nostdcall':
+                self.nostdcall = True
             else:
-                raise IDLError("Unexpected attribute '%s'", aloc)
+                raise IDLError("Unexpected attribute '%s'" % name, aloc)
 
         self.namemap = NameMap()
         for p in paramlist:
             self.namemap.set(p)
 
     def resolve(self, iface):
         self.iface = iface
         self.realtype = self.iface.idl.getName(self.type, self.location)
--- a/xpcom/typelib/xpidl/xpidl_header.c
+++ b/xpcom/typelib/xpidl/xpidl_header.c
@@ -784,26 +784,34 @@ write_type(IDL_tree type_tree, write_typ
  */
 static gboolean
 write_attr_accessor(IDL_tree attr_tree, FILE * outfile,
                     gboolean getter, int mode, const char *className)
 {
     char *attrname = ATTR_IDENT(attr_tree).str;
     const char *binaryname;
     IDL_tree ident = IDL_LIST(IDL_ATTR_DCL(attr_tree).simple_declarations).data;
+    gboolean nostdcall =
+        (IDL_tree_property_get(ATTR_DECLS(attr_tree), "nostdcall") != NULL);
 
     if (mode == AS_DECL) {
         if (IDL_tree_property_get(ident, "deprecated"))
             fputs("MOZ_DEPRECATED ", outfile);
         if (is_method_scriptable(attr_tree, ident))
             fputs("NS_SCRIPTABLE ", outfile);
 
-        fputs("NS_IMETHOD ", outfile);
+        if (nostdcall)
+            fputs("virtual nsresult ", outfile);
+        else
+            fputs("NS_IMETHOD ", outfile);
     } else if (mode == AS_IMPL) {
-        fprintf(outfile, "NS_IMETHODIMP %s::", className);
+        if (nostdcall)
+            fprintf(outfile, "nsresult %s::", className);
+        else
+            fprintf(outfile, "NS_IMETHODIMP %s::", className);
     }
     fprintf(outfile, "%cet",
             getter ? 'G' : 'S');
     binaryname = IDL_tree_property_get(ATTR_DECLS(attr_tree), "binaryname");
     if (binaryname) {
         fprintf(outfile, "%s(",
                 binaryname);
     } else {
@@ -1035,38 +1043,59 @@ write_method_signature(IDL_tree method_t
     struct _IDL_OP_DCL *op = &IDL_OP_DCL(method_tree);
     gboolean no_generated_args = TRUE;
     gboolean op_notxpcom =
         (IDL_tree_property_get(op->ident, "notxpcom") != NULL);
     gboolean op_opt_argc =
         (IDL_tree_property_get(op->ident, "optional_argc") != NULL);
     gboolean op_context =
         (IDL_tree_property_get(op->ident, "implicit_jscontext") != NULL);
+    gboolean op_nostdcall =
+        (IDL_tree_property_get(op->ident, "nostdcall") != NULL);
     const char *name;
     const char *binaryname;
     IDL_tree iter;
 
     if (mode == AS_DECL) {
         if (IDL_tree_property_get(op->ident, "deprecated"))
             fputs("MOZ_DEPRECATED ", outfile);
         if (is_method_scriptable(method_tree, op->ident))
             fputs("NS_SCRIPTABLE ", outfile);
 
-        if (op_notxpcom) {
+        if (op_nostdcall) {
+            fputs("virtual ", outfile);
+            if (op_notxpcom) {
+                if (!write_type(op->op_type_spec, WT_PLAIN, FALSE, outfile))
+                    return FALSE;
+            }
+            else {
+                fputs("nsresult", outfile);
+            }
+        }
+        else if (op_notxpcom) {
             fputs("NS_IMETHOD_(", outfile);
             if (!write_type(op->op_type_spec, WT_PLAIN, FALSE, outfile))
                 return FALSE;
             fputc(')', outfile);
         } else {
             fputs("NS_IMETHOD", outfile);
         }
         fputc(' ', outfile);
     }
     else if (mode == AS_IMPL) {
-        if (op_notxpcom) {
+        if (op_nostdcall) {
+            if (op_notxpcom) {
+                if (!write_type(op->op_type_spec, WT_PLAIN, FALSE, outfile))
+                    return FALSE;
+            }
+            else {
+                fputs("nsresult", outfile);
+            }
+        }
+        else if (op_notxpcom) {
             fputs("NS_IMETHODIMP_(", outfile);
             if (!write_type(op->op_type_spec, WT_PLAIN, FALSE, outfile))
                 return FALSE;
             fputc(')', outfile);
         } else {
             fputs("NS_IMETHODIMP", outfile);
         }
         fputc(' ', outfile);
--- a/xpcom/typelib/xpidl/xpidl_util.c
+++ b/xpcom/typelib/xpidl/xpidl_util.c
@@ -355,16 +355,22 @@ verify_attribute_declaration(IDL_tree at
     /*
      * If the interface isn't scriptable, or the attribute is marked noscript,
      * there's no need to check. This also verifies that we've been called on
      * an interface.
      */
     if (!is_method_scriptable(attr_tree, ident))
         return TRUE;
 
+    if (IDL_tree_property_get(ident, "nostdcall") != NULL) {
+        IDL_tree_error(attr_tree,
+                       "[nostdcall] attribute must not be scriptable");
+        return FALSE;
+    }
+
     /*
      * If it should be scriptable, check that the type is non-native. nsid,
      * domstring, utf8string, cstring, astring are exempted.
      */
     attr_type = IDL_ATTR_DCL(attr_tree).param_type_spec;
 
     if (attr_type != NULL)
     {
@@ -774,17 +780,24 @@ verify_method_declaration(IDL_tree metho
 
     if (IDL_tree_property_get(op->ident, "optional_argc") != NULL &&
         !hasoptional) {
         IDL_tree_error(method_tree,
                        "[optional_argc] method must contain [optional] "
                        "arguments");
         return FALSE;
     }
-    
+
+    if (IDL_tree_property_get(op->ident, "nostdcall") != NULL &&
+        scriptable_method) {
+        IDL_tree_error(method_tree,
+                       "[nostdcall] method must not be scriptable");
+        return FALSE;
+    }
+
     /* XXX q: can return type be nsid? */
     /* Native return type? */
     if (scriptable_method &&
         op->op_type_spec != NULL && UP_IS_NATIVE(op->op_type_spec) &&
         IDL_tree_property_get(op->op_type_spec, "nsid") == NULL &&
         IDL_tree_property_get(op->op_type_spec, "domstring") == NULL &&
         IDL_tree_property_get(op->op_type_spec, "utf8string") == NULL &&
         IDL_tree_property_get(op->op_type_spec, "cstring") == NULL &&