aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings/codegen/Codegen.py
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/bindings/codegen/Codegen.py')
-rw-r--r--components/script/dom/bindings/codegen/Codegen.py5788
1 files changed, 0 insertions, 5788 deletions
diff --git a/components/script/dom/bindings/codegen/Codegen.py b/components/script/dom/bindings/codegen/Codegen.py
deleted file mode 100644
index 6d2cc0bde36..00000000000
--- a/components/script/dom/bindings/codegen/Codegen.py
+++ /dev/null
@@ -1,5788 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
-# You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# Common codegen classes.
-
-import os
-import string
-import operator
-
-from WebIDL import *
-from Configuration import NoSuchDescriptorError
-
-AUTOGENERATED_WARNING_COMMENT = \
- "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n"
-ADDPROPERTY_HOOK_NAME = '_addProperty'
-FINALIZE_HOOK_NAME = '_finalize'
-TRACE_HOOK_NAME = '_trace'
-CONSTRUCT_HOOK_NAME = '_constructor'
-HASINSTANCE_HOOK_NAME = '_hasInstance'
-
-def replaceFileIfChanged(filename, newContents):
- """
- Read a copy of the old file, so that we don't touch it if it hasn't changed.
- Returns True if the file was updated, false otherwise.
- """
- oldFileContents = ""
- try:
- oldFile = open(filename, 'rb')
- oldFileContents = ''.join(oldFile.readlines())
- oldFile.close()
- except:
- pass
-
- if newContents == oldFileContents:
- return False
-
- f = open(filename, 'wb')
- f.write(newContents)
- f.close()
-
-def toStringBool(arg):
- return str(not not arg).lower()
-
-def toBindingNamespace(arg):
- return re.sub("((_workers)?$)", "Binding\\1", arg);
-
-class CGThing():
- """
- Abstract base class for things that spit out code.
- """
- def __init__(self):
- pass # Nothing for now
- def declare(self):
- """Produce code for a header file."""
- assert(False) # Override me!
- def define(self):
- """Produce code for a cpp file."""
- assert(False) # Override me!
-
-class CGNativePropertyHooks(CGThing):
- """
- Generate a NativePropertyHooks for a given descriptor
- """
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
- def declare(self):
- if self.descriptor.workers:
- return ""
- return "extern const NativePropertyHooks NativeHooks;\n"
- def define(self):
- if self.descriptor.workers:
- return ""
- if self.descriptor.concrete and self.descriptor.proxy:
- resolveOwnProperty = "ResolveOwnProperty"
- enumerateOwnProperties = "EnumerateOwnProperties"
- else:
- enumerateOwnProperties = resolveOwnProperty = "NULL"
- parent = self.descriptor.interface.parent
- parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::NativeHooks"
- if parent else 'NULL')
- return """
-const NativePropertyHooks NativeHooks = { %s, ResolveProperty, %s, EnumerateProperties, %s };
-""" % (resolveOwnProperty, enumerateOwnProperties, parentHooks)
-
-def DOMClass(descriptor):
- protoList = ['prototypes::id::' + proto for proto in descriptor.prototypeChain]
- # Pad out the list to the right length with _ID_Count so we
- # guarantee that all the lists are the same length. _ID_Count
- # is never the ID of any prototype, so it's safe to use as
- # padding.
- protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList)))
- prototypeChainString = ', '.join(protoList)
- nativeHooks = "NULL" if descriptor.workers else "&NativeHooks"
- return """{
- { %s },
- %s, %s
-}""" % (prototypeChainString, toStringBool(descriptor.nativeIsISupports),
- nativeHooks)
-
-class CGDOMJSClass(CGThing):
- """
- Generate a DOMJSClass for a given descriptor
- """
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
- def declare(self):
- return "extern DOMJSClass Class;\n"
- def define(self):
- traceHook = TRACE_HOOK_NAME if self.descriptor.customTrace else 'NULL'
- return """
-DOMJSClass Class = {
- { "%s",
- JSCLASS_IS_DOMJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(1),
- %s, /* addProperty */
- JS_PropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- %s, /* finalize */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* hasInstance */
- NULL, /* construct */
- %s, /* trace */
- JSCLASS_NO_INTERNAL_MEMBERS
- },
- %s
-};
-""" % (self.descriptor.interface.identifier.name,
- ADDPROPERTY_HOOK_NAME if self.descriptor.concrete and not self.descriptor.workers and self.descriptor.wrapperCache else 'JS_PropertyStub',
- FINALIZE_HOOK_NAME, traceHook,
- CGIndenter(CGGeneric(DOMClass(self.descriptor))).define())
-
-class CGPrototypeJSClass(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
- def declare(self):
- # We're purely for internal consumption
- return ""
- def define(self):
- return """static JSClass PrototypeClass = {
- "%sPrototype",
- JSCLASS_HAS_RESERVED_SLOTS(1),
- JS_PropertyStub, /* addProperty */
- JS_PropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- NULL, /* finalize */
- NULL, /* checkAccess */
- NULL, /* call */
- NULL, /* hasInstance */
- NULL, /* construct */
- NULL, /* trace */
- JSCLASS_NO_INTERNAL_MEMBERS
-};
-""" % (self.descriptor.interface.identifier.name)
-
-class CGInterfaceObjectJSClass(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
- def declare(self):
- # We're purely for internal consumption
- return ""
- def define(self):
- if not self.descriptor.hasInstanceInterface:
- return ""
- ctorname = "NULL" if not self.descriptor.interface.ctor() else CONSTRUCT_HOOK_NAME
- hasinstance = HASINSTANCE_HOOK_NAME
- return """
-static JSClass InterfaceObjectClass = {
- "Function", 0,
- JS_PropertyStub, /* addProperty */
- JS_PropertyStub, /* delProperty */
- JS_PropertyStub, /* getProperty */
- JS_StrictPropertyStub, /* setProperty */
- JS_EnumerateStub,
- JS_ResolveStub,
- JS_ConvertStub,
- NULL, /* finalize */
- NULL, /* checkAccess */
- %s, /* call */
- %s, /* hasInstance */
- %s, /* construct */
- NULL, /* trace */
- JSCLASS_NO_INTERNAL_MEMBERS
-};
-""" % (ctorname, hasinstance, ctorname)
-
-class CGList(CGThing):
- """
- Generate code for a list of GCThings. Just concatenates them together, with
- an optional joiner string. "\n" is a common joiner.
- """
- def __init__(self, children, joiner=""):
- CGThing.__init__(self)
- self.children = children
- self.joiner = joiner
- def append(self, child):
- self.children.append(child)
- def prepend(self, child):
- self.children.insert(0, child)
- def join(self, generator):
- return self.joiner.join(filter(lambda s: len(s) > 0, (child for child in generator)))
- def declare(self):
- return self.join(child.declare() for child in self.children if child is not None)
- def define(self):
- return self.join(child.define() for child in self.children if child is not None)
-
-class CGGeneric(CGThing):
- """
- A class that spits out a fixed string into the codegen. Can spit out a
- separate string for the declaration too.
- """
- def __init__(self, define="", declare=""):
- self.declareText = declare
- self.defineText = define
- def declare(self):
- return self.declareText
- def define(self):
- return self.defineText
-
-# We'll want to insert the indent at the beginnings of lines, but we
-# don't want to indent empty lines. So only indent lines that have a
-# non-newline character on them.
-lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
-class CGIndenter(CGThing):
- """
- A class that takes another CGThing and generates code that indents that
- CGThing by some number of spaces. The default indent is two spaces.
- """
- def __init__(self, child, indentLevel=2, declareOnly=False):
- CGThing.__init__(self)
- self.child = child
- self.indent = " " * indentLevel
- self.declareOnly = declareOnly
- def declare(self):
- decl = self.child.declare()
- if decl is not "":
- return re.sub(lineStartDetector, self.indent, decl)
- else:
- return ""
- def define(self):
- defn = self.child.define()
- if defn is not "" and not self.declareOnly:
- return re.sub(lineStartDetector, self.indent, defn)
- else:
- return defn
-
-class CGWrapper(CGThing):
- """
- Generic CGThing that wraps other CGThings with pre and post text.
- """
- def __init__(self, child, pre="", post="", declarePre=None,
- declarePost=None, definePre=None, definePost=None,
- declareOnly=False, defineOnly=False, reindent=False):
- CGThing.__init__(self)
- self.child = child
- self.declarePre = declarePre or pre
- self.declarePost = declarePost or post
- self.definePre = definePre or pre
- self.definePost = definePost or post
- self.declareOnly = declareOnly
- self.defineOnly = defineOnly
- self.reindent = reindent
- def declare(self):
- if self.defineOnly:
- return ''
- decl = self.child.declare()
- if self.reindent:
- # We don't use lineStartDetector because we don't want to
- # insert whitespace at the beginning of our _first_ line.
- decl = stripTrailingWhitespace(
- decl.replace("\n", "\n" + (" " * len(self.declarePre))))
- return self.declarePre + decl + self.declarePost
- def define(self):
- if self.declareOnly:
- return ''
- defn = self.child.define()
- if self.reindent:
- # We don't use lineStartDetector because we don't want to
- # insert whitespace at the beginning of our _first_ line.
- defn = stripTrailingWhitespace(
- defn.replace("\n", "\n" + (" " * len(self.definePre))))
- return self.definePre + defn + self.definePost
-
-class CGIfWrapper(CGWrapper):
- def __init__(self, child, condition):
- pre = CGWrapper(CGGeneric(condition), pre="if (", post=") {\n",
- reindent=True)
- CGWrapper.__init__(self, CGIndenter(child), pre=pre.define(),
- post="\n}")
-
-class CGNamespace(CGWrapper):
- def __init__(self, namespace, child, declareOnly=False):
- pre = "namespace %s {\n" % namespace
- post = "} // namespace %s\n" % namespace
- CGWrapper.__init__(self, child, pre=pre, post=post,
- declareOnly=declareOnly)
- @staticmethod
- def build(namespaces, child, declareOnly=False):
- """
- Static helper method to build multiple wrapped namespaces.
- """
- if not namespaces:
- return CGWrapper(child, declareOnly=declareOnly)
- inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly)
- return CGNamespace(namespaces[0], inner, declareOnly=declareOnly)
-
-class CGIncludeGuard(CGWrapper):
- """
- Generates include guards for a header.
- """
- def __init__(self, prefix, child):
- """|prefix| is the filename without the extension."""
- define = 'mozilla_dom_%s_h__' % prefix
- CGWrapper.__init__(self, child,
- declarePre='#ifndef %s\n#define %s\n\n' % (define, define),
- declarePost='\n#endif // %s\n' % define)
-
-def getTypes(descriptor):
- """
- Get all argument and return types for all members of the descriptor
- """
- members = [m for m in descriptor.interface.members]
- if descriptor.interface.ctor():
- members.append(descriptor.interface.ctor())
- signatures = [s for m in members if m.isMethod() for s in m.signatures()]
- types = []
- for s in signatures:
- assert len(s) == 2
- (returnType, arguments) = s
- types.append(returnType)
- types.extend([a.type for a in arguments])
-
- types.extend(a.type for a in members if a.isAttr())
- return types
-
-class CGHeaders(CGWrapper):
- """
- Generates the appropriate include statements.
- """
- def __init__(self, descriptors, dictionaries, declareIncludes,
- defineIncludes, child):
- """
- Builds a set of includes to cover |descriptors|.
-
- Also includes the files in |declareIncludes| in the header
- file and the files in |defineIncludes| in the .cpp.
- """
-
- # Determine the filenames for which we need headers.
- interfaceDeps = [d.interface for d in descriptors]
- ancestors = []
- for iface in interfaceDeps:
- while iface.parent:
- ancestors.append(iface.parent)
- iface = iface.parent
- interfaceDeps.extend(ancestors)
- bindingIncludes = set(self.getDeclarationFilename(d) for d in interfaceDeps)
-
- # Grab all the implementation declaration files we need.
- implementationIncludes = set(d.headerFile for d in descriptors)
-
- # Now find all the things we'll need as arguments because we
- # need to wrap or unwrap them.
- bindingHeaders = set()
- for d in descriptors:
- types = getTypes(d)
- for dictionary in dictionaries:
- curDict = dictionary
- while curDict:
- types.extend([m.type for m in curDict.members])
- curDict = curDict.parent
-
- for t in types:
- if t.unroll().isUnion():
- # UnionConversions.h includes UnionTypes.h
- bindingHeaders.add("mozilla/dom/UnionConversions.h")
- elif t.unroll().isInterface():
- if t.unroll().isSpiderMonkeyInterface():
- bindingHeaders.add("jsfriendapi.h")
- bindingHeaders.add("mozilla/dom/TypedArray.h")
- else:
- typeDesc = d.getDescriptor(t.unroll().inner.identifier.name)
- if typeDesc is not None:
- implementationIncludes.add(typeDesc.headerFile)
- bindingHeaders.add(self.getDeclarationFilename(typeDesc.interface))
- elif t.unroll().isDictionary():
- bindingHeaders.add(self.getDeclarationFilename(t.unroll().inner))
-
- declareIncludes = set(declareIncludes)
- for d in dictionaries:
- if d.parent:
- declareIncludes.add(self.getDeclarationFilename(d.parent))
- bindingHeaders.add(self.getDeclarationFilename(d))
-
- # Let the machinery do its thing.
- def _includeString(includes):
- return ''.join(['#include "%s"\n' % i for i in includes]) + '\n'
- CGWrapper.__init__(self, child,
- declarePre=_includeString(sorted(declareIncludes)),
- definePre=_includeString(sorted(set(defineIncludes) |
- bindingIncludes |
- bindingHeaders |
- implementationIncludes)))
- @staticmethod
- def getDeclarationFilename(decl):
- # Use our local version of the header, not the exported one, so that
- # test bindings, which don't export, will work correctly.
- basename = os.path.basename(decl.filename())
- return basename.replace('.webidl', 'Binding.h')
-
-def SortedTuples(l):
- """
- Sort a list of tuples based on the first item in the tuple
- """
- return sorted(l, key=operator.itemgetter(0))
-
-def SortedDictValues(d):
- """
- Returns a list of values from the dict sorted by key.
- """
- # Create a list of tuples containing key and value, sorted on key.
- d = SortedTuples(d.items())
- # We're only interested in the values.
- return (i[1] for i in d)
-
-def UnionTypes(descriptors):
- """
- Returns a tuple containing a set of header filenames to include, a set of
- tuples containing a type declaration and a boolean if the type is a struct
- for member types of the unions and a CGList containing CGUnionStructs for
- every union.
- """
-
- # Now find all the things we'll need as arguments and return values because
- # we need to wrap or unwrap them.
- headers = set()
- declarations = set()
- unionStructs = dict()
- for d in descriptors:
- if d.interface.isExternal():
- continue
-
- for t in getTypes(d):
- t = t.unroll()
- if t.isUnion():
- name = str(t)
- if not name in unionStructs:
- unionStructs[name] = CGUnionStruct(t, d)
- for f in t.flatMemberTypes:
- f = f.unroll()
- if f.isInterface():
- if f.isSpiderMonkeyInterface():
- headers.add("jsfriendapi.h")
- headers.add("mozilla/dom/TypedArray.h")
- else:
- typeDesc = d.getDescriptor(f.inner.identifier.name)
- if typeDesc is not None:
- declarations.add((typeDesc.nativeType, False))
- elif f.isDictionary():
- declarations.add((f.inner.identifier.name, True))
-
- return (headers, declarations, CGList(SortedDictValues(unionStructs), "\n"))
-
-def UnionConversions(descriptors):
- """
- Returns a CGThing to declare all union argument conversion helper structs.
- """
- # Now find all the things we'll need as arguments because we
- # need to unwrap them.
- unionConversions = dict()
- for d in descriptors:
- if d.interface.isExternal():
- continue
-
- def addUnionTypes(type):
- if type.isUnion():
- type = type.unroll()
- name = str(type)
- if not name in unionConversions:
- unionConversions[name] = CGUnionConversionStruct(type, d)
-
- members = [m for m in d.interface.members]
- if d.interface.ctor():
- members.append(d.interface.ctor())
- signatures = [s for m in members if m.isMethod() for s in m.signatures()]
- for s in signatures:
- assert len(s) == 2
- (_, arguments) = s
- for a in arguments:
- addUnionTypes(a.type)
-
- for m in members:
- if m.isAttr() and not m.readonly:
- addUnionTypes(m.type)
-
- return CGWrapper(CGList(SortedDictValues(unionConversions), "\n"),
- post="\n\n")
-
-class Argument():
- """
- A class for outputting the type and name of an argument
- """
- def __init__(self, argType, name):
- self.argType = argType
- self.name = name
- def __str__(self):
- return self.argType + ' ' + self.name
-
-class CGAbstractMethod(CGThing):
- """
- An abstract class for generating code for a method. Subclasses
- should override definition_body to create the actual code.
-
- descriptor is the descriptor for the interface the method is associated with
-
- name is the name of the method as a string
-
- returnType is the IDLType of the return value
-
- args is a list of Argument objects
-
- inline should be True to generate an inline method, whose body is
- part of the declaration.
-
- alwaysInline should be True to generate an inline method annotated with
- MOZ_ALWAYS_INLINE.
-
- static should be True to generate a static method, which only has
- a definition.
-
- If templateArgs is not None it should be a list of strings containing
- template arguments, and the function will be templatized using those
- arguments.
- """
- def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, templateArgs=None):
- CGThing.__init__(self)
- self.descriptor = descriptor
- self.name = name
- self.returnType = returnType
- self.args = args
- self.inline = inline
- self.alwaysInline = alwaysInline
- self.static = static
- self.templateArgs = templateArgs
- def _argstring(self):
- return ', '.join([str(a) for a in self.args])
- def _template(self):
- if self.templateArgs is None:
- return ''
- return 'template <%s>\n' % ', '.join(self.templateArgs)
- def _decorators(self):
- decorators = []
- if self.alwaysInline:
- decorators.append('MOZ_ALWAYS_INLINE')
- elif self.inline:
- decorators.append('inline')
- if self.static:
- decorators.append('static')
- decorators.append(self.returnType)
- maybeNewline = " " if self.inline else "\n"
- return ' '.join(decorators) + maybeNewline
- def declare(self):
- if self.inline:
- return self._define()
- return "%s%s%s(%s);\n" % (self._template(), self._decorators(), self.name, self._argstring())
- def _define(self):
- return self.definition_prologue() + "\n" + self.definition_body() + self.definition_epilogue()
- def define(self):
- return "" if self.inline else self._define()
- def definition_prologue(self):
- return "%s%s%s(%s)\n{" % (self._template(), self._decorators(),
- self.name, self._argstring())
- def definition_epilogue(self):
- return "\n}\n"
- def definition_body(self):
- assert(False) # Override me!
-
-class CGAbstractStaticMethod(CGAbstractMethod):
- """
- Abstract base class for codegen of implementation-only (no
- declaration) static methods.
- """
- def __init__(self, descriptor, name, returnType, args):
- CGAbstractMethod.__init__(self, descriptor, name, returnType, args,
- inline=False, static=True)
- def declare(self):
- # We only have implementation
- return ""
-
-class CGAbstractClassHook(CGAbstractStaticMethod):
- """
- Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw
- 'this' unwrapping as it assumes that the unwrapped type is always known.
- """
- def __init__(self, descriptor, name, returnType, args):
- CGAbstractStaticMethod.__init__(self, descriptor, name, returnType,
- args)
-
- def definition_body_prologue(self):
- return """
- %s* self = UnwrapDOMObject<%s>(obj, eRegularDOMObject);
-""" % (self.descriptor.nativeType, self.descriptor.nativeType)
-
- def definition_body(self):
- return self.definition_body_prologue() + self.generate_code()
-
- def generate_code(self):
- # Override me
- assert(False)
-
-class CGAddPropertyHook(CGAbstractClassHook):
- """
- A hook for addProperty, used to preserve our wrapper from GC.
- """
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'),
- Argument('JSHandleId', 'id'), Argument('JSMutableHandleValue', 'vp')]
- CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME,
- 'JSBool', args)
-
- def generate_code(self):
- # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=774279
- # Using a real trace hook might enable us to deal with non-nsISupports
- # wrappercached things here.
- assert self.descriptor.nativeIsISupports
- return """ nsContentUtils::PreserveWrapper(reinterpret_cast<nsISupports*>(self), self);
- return true;"""
-
-def finalizeHook(descriptor, hookName, context):
- if descriptor.customFinalize:
- return """if (self) {
- self->%s(%s);
-}""" % (hookName, context)
- clearWrapper = "ClearWrapper(self, self);\n" if descriptor.wrapperCache else ""
- if descriptor.workers:
- release = "self->Release();"
- else:
- assert descriptor.nativeIsISupports
- release = """XPCJSRuntime *rt = nsXPConnect::GetRuntimeInstance();
-if (rt) {
- rt->DeferredRelease(reinterpret_cast<nsISupports*>(self));
-} else {
- NS_RELEASE(self);
-}"""
- return clearWrapper + release
-
-class CGClassFinalizeHook(CGAbstractClassHook):
- """
- A hook for finalize, used to release our native object.
- """
- def __init__(self, descriptor):
- args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'obj')]
- CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
- 'void', args)
-
- def generate_code(self):
- return CGIndenter(CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name))).define()
-
-class CGClassTraceHook(CGAbstractClassHook):
- """
- A hook to trace through our native object; used for GC and CC
- """
- def __init__(self, descriptor):
- args = [Argument('JSTracer*', 'trc'), Argument('JSObject*', 'obj')]
- CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void',
- args)
-
- def generate_code(self):
- return """ if (self) {
- self->%s(%s);
- }""" % (self.name, self.args[0].name)
-
-class CGClassConstructHook(CGAbstractStaticMethod):
- """
- JS-visible constructor for our objects
- """
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'), Argument('JS::Value*', 'vp')]
- CGAbstractStaticMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME,
- 'JSBool', args)
- self._ctor = self.descriptor.interface.ctor()
-
- def define(self):
- if not self._ctor:
- return ""
- return CGAbstractStaticMethod.define(self)
-
- def definition_body(self):
- return self.generate_code()
-
- def generate_code(self):
- preamble = """
- JSObject* obj = JS_GetGlobalForObject(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
-"""
- if self.descriptor.workers:
- preArgs = ["cx", "obj"]
- else:
- preamble += """
- nsISupports* global;
- xpc_qsSelfRef globalRef;
- {
- nsresult rv;
- JS::Value val = OBJECT_TO_JSVAL(obj);
- rv = xpc_qsUnwrapArg<nsISupports>(cx, val, &global, &globalRef.ptr, &val);
- if (NS_FAILED(rv)) {
- return Throw<true>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
- }
- }
-"""
- preArgs = ["global"]
-
- name = self._ctor.identifier.name
- nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
- callGenerator = CGMethodCall(preArgs, nativeName, True,
- self.descriptor, self._ctor)
- return preamble + callGenerator.define();
-
-class CGClassHasInstanceHook(CGAbstractStaticMethod):
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'),
- Argument('JSMutableHandleValue', 'vp'), Argument('JSBool*', 'bp')]
- CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME,
- 'JSBool', args)
-
- def define(self):
- if not self.descriptor.hasInstanceInterface:
- return ""
- return CGAbstractStaticMethod.define(self)
-
- def definition_body(self):
- return self.generate_code()
-
- def generate_code(self):
- return """ if (!vp.isObject()) {
- *bp = false;
- return true;
- }
-
- jsval protov;
- if (!JS_GetProperty(cx, obj, "prototype", &protov))
- return false;
- if (!protov.isObject()) {
- JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_PROTOTYPE,
- "%s");
- return false;
- }
- JSObject *objProto = &protov.toObject();
-
- JSObject* instance = &vp.toObject();
- JSObject* proto;
- if (!JS_GetPrototype(cx, instance, &proto))
- return false;
- while (proto) {
- if (proto == objProto) {
- *bp = true;
- return true;
- }
- if (!JS_GetPrototype(cx, proto, &proto))
- return false;
- }
-
- nsISupports* native =
- nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, instance);
- nsCOMPtr<%s> qiResult = do_QueryInterface(native);
- *bp = !!qiResult;
- return true;
-""" % (self.descriptor.name, self.descriptor.hasInstanceInterface)
-
-def isChromeOnly(m):
- return m.getExtendedAttribute("ChromeOnly")
-
-class PropertyDefiner:
- """
- A common superclass for defining things on prototype objects.
-
- Subclasses should implement generateArray to generate the actual arrays of
- things we're defining. They should also set self.chrome to the list of
- things exposed to chrome and self.regular to the list of things exposed to
- web pages. self.chrome must be a superset of self.regular but also include
- all the ChromeOnly stuff.
- """
- def __init__(self, descriptor, name):
- self.descriptor = descriptor
- self.name = name
- # self.prefCacheData will store an array of (prefname, bool*)
- # pairs for our bool var caches. generateArray will fill it
- # in as needed.
- self.prefCacheData = []
- def hasChromeOnly(self):
- return len(self.chrome) > len(self.regular)
- def hasNonChromeOnly(self):
- return len(self.regular) > 0
- def variableName(self, chrome):
- if chrome and self.hasChromeOnly():
- return "sChrome" + self.name
- if self.hasNonChromeOnly():
- return "s" + self.name
- return "NULL"
- def usedForXrays(self, chrome):
- # We only need Xrays for methods, attributes and constants. And we only
- # need them for the non-chrome ones if we have no chromeonly things.
- # Otherwise (we have chromeonly attributes) we need Xrays for the chrome
- # methods/attributes/constants. Finally, in workers there are no Xrays.
- return ((self.name is "Methods" or self.name is "Attributes" or
- self.name is "Constants") and
- chrome == self.hasChromeOnly() and
- not self.descriptor.workers)
-
- def __str__(self):
- # We only need to generate id arrays for things that will end
- # up used via ResolveProperty or EnumerateProperties.
- str = self.generateArray(self.regular, self.variableName(False),
- self.usedForXrays(False))
- if self.hasChromeOnly():
- str += self.generateArray(self.chrome, self.variableName(True),
- self.usedForXrays(True))
- return str
-
- @staticmethod
- def getControllingPref(interfaceMember):
- prefName = interfaceMember.getExtendedAttribute("Pref")
- if prefName is None:
- return None
- # It's a list of strings
- assert(len(prefName) is 1)
- assert(prefName[0] is not None)
- return prefName[0]
-
- def generatePrefableArray(self, array, name, specTemplate, specTerminator,
- specType, getPref, getDataTuple, doIdArrays):
- """
- This method generates our various arrays.
-
- array is an array of interface members as passed to generateArray
-
- name is the name as passed to generateArray
-
- specTemplate is a template for each entry of the spec array
-
- specTerminator is a terminator for the spec array (inserted every time
- our controlling pref changes and at the end of the array)
-
- specType is the actual typename of our spec
-
- getPref is a callback function that takes an array entry and returns
- the corresponding pref value.
-
- getDataTuple is a callback function that takes an array entry and
- returns a tuple suitable for substitution into specTemplate.
- """
-
- # We want to generate a single list of specs, but with specTerminator
- # inserted at every point where the pref name controlling the member
- # changes. That will make sure the order of the properties as exposed
- # on the interface and interface prototype objects does not change when
- # pref control is added to members while still allowing us to define all
- # the members in the smallest number of JSAPI calls.
- assert(len(array) is not 0)
- lastPref = getPref(array[0]) # So we won't put a specTerminator
- # at the very front of the list.
- specs = []
- prefableSpecs = []
- if doIdArrays:
- prefableIds = []
-
- prefableTemplate = ' { true, &%s[%d] }'
- prefCacheTemplate = '&%s[%d].enabled'
- def switchToPref(props, pref):
- # Remember the info about where our pref-controlled
- # booleans live.
- if pref is not None:
- props.prefCacheData.append(
- (pref, prefCacheTemplate % (name, len(prefableSpecs)))
- )
- # Set up pointers to the new sets of specs and ids
- # inside prefableSpecs and prefableIds
- prefableSpecs.append(prefableTemplate %
- (name + "_specs", len(specs)))
-
- switchToPref(self, lastPref)
-
- for member in array:
- curPref = getPref(member)
- if lastPref != curPref:
- # Terminate previous list
- specs.append(specTerminator)
- # And switch to our new pref
- switchToPref(self, curPref)
- lastPref = curPref
- # And the actual spec
- specs.append(specTemplate % getDataTuple(member))
- specs.append(specTerminator)
- prefableSpecs.append(" { false, NULL }");
-
- arrays = (("static %s %s_specs[] = {\n" +
- ',\n'.join(specs) + "\n" +
- "};\n\n" +
- "static Prefable<%s> %s[] = {\n" +
- ',\n'.join(prefableSpecs) + "\n" +
- "};\n\n") % (specType, name, specType, name))
- if doIdArrays:
- arrays += ("static jsid %s_ids[%i] = { JSID_VOID };\n\n" %
- (name, len(specs)))
- return arrays
-
-
-# The length of a method is the maximum of the lengths of the
-# argument lists of all its overloads.
-def methodLength(method):
- signatures = method.signatures()
- return max([len(arguments) for (retType, arguments) in signatures])
-
-class MethodDefiner(PropertyDefiner):
- """
- A class for defining methods on a prototype object.
- """
- def __init__(self, descriptor, name, static):
- PropertyDefiner.__init__(self, descriptor, name)
-
- # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822
- # We should be able to check for special operations without an
- # identifier. For now we check if the name starts with __
- methods = [m for m in descriptor.interface.members if
- m.isMethod() and m.isStatic() == static and
- not m.isIdentifierLess()]
- self.chrome = [{"name": m.identifier.name,
- "length": methodLength(m),
- "flags": "JSPROP_ENUMERATE",
- "pref": PropertyDefiner.getControllingPref(m) }
- for m in methods]
- self.regular = [{"name": m.identifier.name,
- "length": methodLength(m),
- "flags": "JSPROP_ENUMERATE",
- "pref": PropertyDefiner.getControllingPref(m) }
- for m in methods if not isChromeOnly(m)]
-
- # FIXME Check for an existing iterator on the interface first.
- if any(m.isGetter() and m.isIndexed() for m in methods):
- self.chrome.append({"name": 'iterator',
- "methodInfo": False,
- "nativeName": "JS_ArrayIterator",
- "length": 0,
- "flags": "JSPROP_ENUMERATE",
- "pref": None })
- self.regular.append({"name": 'iterator',
- "methodInfo": False,
- "nativeName": "JS_ArrayIterator",
- "length": 0,
- "flags": "JSPROP_ENUMERATE",
- "pref": None })
-
- if not descriptor.interface.parent and not static and not descriptor.workers:
- self.chrome.append({"name": 'QueryInterface',
- "methodInfo": False,
- "length": 1,
- "flags": "0",
- "pref": None })
-
- if static:
- if not descriptor.interface.hasInterfaceObject():
- # static methods go on the interface object
- assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
- else:
- if not descriptor.interface.hasInterfacePrototypeObject():
- # non-static methods go on the interface prototype object
- assert not self.hasChromeOnly() and not self.hasNonChromeOnly()
-
- def generateArray(self, array, name, doIdArrays):
- if len(array) == 0:
- return ""
-
- def pref(m):
- return m["pref"]
-
- def specData(m):
- if m.get("methodInfo", True):
- jitinfo = ("&%s_methodinfo" % m["name"])
- accessor = "genericMethod"
- else:
- jitinfo = "nullptr"
- accessor = m.get("nativeName", m["name"])
- return (m["name"], accessor, jitinfo, m["length"], m["flags"])
-
- return self.generatePrefableArray(
- array, name,
- ' JS_FNINFO("%s", %s, %s, %s, %s)',
- ' JS_FS_END',
- 'JSFunctionSpec',
- pref, specData, doIdArrays)
-
-class AttrDefiner(PropertyDefiner):
- def __init__(self, descriptor, name):
- PropertyDefiner.__init__(self, descriptor, name)
- self.name = name
- self.chrome = [m for m in descriptor.interface.members if m.isAttr()]
- self.regular = [m for m in self.chrome if not isChromeOnly(m)]
-
- def generateArray(self, array, name, doIdArrays):
- if len(array) == 0:
- return ""
-
- def flags(attr):
- return "JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS"
-
- def getter(attr):
- native = ("genericLenientGetter" if attr.hasLenientThis()
- else "genericGetter")
- return ("{(JSPropertyOp)%(native)s, &%(name)s_getterinfo}"
- % {"name" : attr.identifier.name,
- "native" : native})
-
- def setter(attr):
- if attr.readonly:
- return "JSOP_NULLWRAPPER"
- native = ("genericLenientSetter" if attr.hasLenientThis()
- else "genericSetter")
- return ("{(JSStrictPropertyOp)%(native)s, &%(name)s_setterinfo}"
- % {"name" : attr.identifier.name,
- "native" : native})
-
- def specData(attr):
- return (attr.identifier.name, flags(attr), getter(attr),
- setter(attr))
-
- return self.generatePrefableArray(
- array, name,
- ' { "%s", 0, %s, %s, %s}',
- ' { 0, 0, 0, JSOP_NULLWRAPPER, JSOP_NULLWRAPPER }',
- 'JSPropertySpec',
- PropertyDefiner.getControllingPref, specData, doIdArrays)
-
-class ConstDefiner(PropertyDefiner):
- """
- A class for definining constants on the interface object
- """
- def __init__(self, descriptor, name):
- PropertyDefiner.__init__(self, descriptor, name)
- self.name = name
- self.chrome = [m for m in descriptor.interface.members if m.isConst()]
- self.regular = [m for m in self.chrome if not isChromeOnly(m)]
-
- def generateArray(self, array, name, doIdArrays):
- if len(array) == 0:
- return ""
-
- def specData(const):
- return (const.identifier.name,
- convertConstIDLValueToJSVal(const.value))
-
- return self.generatePrefableArray(
- array, name,
- ' { "%s", %s }',
- ' { 0, JSVAL_VOID }',
- 'ConstantSpec',
- PropertyDefiner.getControllingPref, specData, doIdArrays)
-
-class PropertyArrays():
- def __init__(self, descriptor):
- self.staticMethods = MethodDefiner(descriptor, "StaticMethods", True)
- self.methods = MethodDefiner(descriptor, "Methods", False)
- self.attrs = AttrDefiner(descriptor, "Attributes")
- self.consts = ConstDefiner(descriptor, "Constants")
-
- @staticmethod
- def arrayNames():
- return [ "staticMethods", "methods", "attrs", "consts" ]
-
- @staticmethod
- def xrayRelevantArrayNames():
- return [ "methods", "attrs", "consts" ]
-
- def hasChromeOnly(self):
- return reduce(lambda b, a: b or getattr(self, a).hasChromeOnly(),
- self.arrayNames(), False)
- def variableNames(self, chrome):
- names = {}
- for array in self.arrayNames():
- names[array] = getattr(self, array).variableName(chrome)
- return names
- def __str__(self):
- define = ""
- for array in self.arrayNames():
- define += str(getattr(self, array))
- return define
-
-class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
- """
- Generate the CreateInterfaceObjects method for an interface descriptor.
-
- properties should be a PropertyArrays instance.
- """
- def __init__(self, descriptor, properties):
- args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
- Argument('JSObject*', 'aReceiver')]
- CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'JSObject*', args)
- self.properties = properties
- def definition_body(self):
- protoChain = self.descriptor.prototypeChain
- if len(protoChain) == 1:
- getParentProto = "JS_GetObjectPrototype(aCx, aGlobal)"
- else:
- parentProtoName = self.descriptor.prototypeChain[-2]
- getParentProto = ("%s::GetProtoObject(aCx, aGlobal, aReceiver)" %
- toBindingNamespace(parentProtoName))
-
- needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
- needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject()
-
- # if we don't need to create anything, why are we generating this?
- assert needInterfaceObject or needInterfacePrototypeObject
-
- idsToInit = []
- # There is no need to init any IDs in workers, because worker bindings
- # don't have Xrays.
- if not self.descriptor.workers:
- for var in self.properties.xrayRelevantArrayNames():
- props = getattr(self.properties, var)
- # We only have non-chrome ids to init if we have no chrome ids.
- if props.hasChromeOnly():
- idsToInit.append(props.variableName(True))
- elif props.hasNonChromeOnly():
- idsToInit.append(props.variableName(False))
- if len(idsToInit) > 0:
- initIds = CGList(
- [CGGeneric("!InitIds(aCx, %s, %s_ids)" % (varname, varname)) for
- varname in idsToInit], ' ||\n')
- if len(idsToInit) > 1:
- initIds = CGWrapper(initIds, pre="(", post=")", reindent=True)
- initIds = CGList(
- [CGGeneric("%s_ids[0] == JSID_VOID &&" % idsToInit[0]), initIds],
- "\n")
- initIds = CGWrapper(initIds, pre="if (", post=") {", reindent=True)
- initIds = CGList(
- [initIds,
- CGGeneric((" %s_ids[0] = JSID_VOID;\n"
- " return NULL;") % idsToInit[0]),
- CGGeneric("}")],
- "\n")
- else:
- initIds = None
-
- prefCacheData = []
- for var in self.properties.arrayNames():
- props = getattr(self.properties, var)
- prefCacheData.extend(props.prefCacheData)
- if len(prefCacheData) is not 0:
- prefCacheData = [
- CGGeneric('Preferences::AddBoolVarCache(%s, "%s");' % (ptr, pref)) for
- (pref, ptr) in prefCacheData]
- prefCache = CGWrapper(CGIndenter(CGList(prefCacheData, "\n")),
- pre=("static bool sPrefCachesInited = false;\n"
- "if (!sPrefCachesInited) {\n"
- " sPrefCachesInited = true;\n"),
- post="\n}")
- else:
- prefCache = None
-
- getParentProto = ("JSObject* parentProto = %s;\n" +
- "if (!parentProto) {\n" +
- " return NULL;\n" +
- "}\n") % getParentProto
-
- needInterfaceObjectClass = (needInterfaceObject and
- self.descriptor.hasInstanceInterface)
- needConstructor = (needInterfaceObject and
- not self.descriptor.hasInstanceInterface)
- if self.descriptor.interface.ctor():
- constructHook = CONSTRUCT_HOOK_NAME
- constructArgs = methodLength(self.descriptor.interface.ctor())
- else:
- constructHook = "ThrowingConstructor"
- constructArgs = 0
-
- if self.descriptor.concrete:
- if self.descriptor.proxy:
- domClass = "&Class"
- else:
- domClass = "&Class.mClass"
- else:
- domClass = "nullptr"
-
- call = """return dom::CreateInterfaceObjects(aCx, aGlobal, aReceiver, parentProto,
- %s, %s, %s, %d,
- %s,
- %%(methods)s, %%(attrs)s,
- %%(consts)s, %%(staticMethods)s,
- %s);""" % (
- "&PrototypeClass" if needInterfacePrototypeObject else "NULL",
- "&InterfaceObjectClass" if needInterfaceObjectClass else "NULL",
- constructHook if needConstructor else "NULL",
- constructArgs,
- domClass,
- '"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "NULL")
- if self.properties.hasChromeOnly():
- if self.descriptor.workers:
- accessCheck = "mozilla::dom::workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker()"
- else:
- accessCheck = "xpc::AccessCheck::isChrome(js::GetObjectCompartment(aGlobal))"
- chrome = CGIfWrapper(CGGeneric(call % self.properties.variableNames(True)),
- accessCheck)
- chrome = CGWrapper(chrome, pre="\n\n")
- else:
- chrome = None
-
- functionBody = CGList(
- [CGGeneric(getParentProto), initIds, prefCache, chrome,
- CGGeneric(call % self.properties.variableNames(False))],
- "\n\n")
- return CGIndenter(functionBody).define()
-
-class CGGetPerInterfaceObject(CGAbstractMethod):
- """
- A method for getting a per-interface object (a prototype object or interface
- constructor object).
- """
- def __init__(self, descriptor, name, idPrefix=""):
- args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aGlobal'),
- Argument('JSObject*', 'aReceiver')]
- CGAbstractMethod.__init__(self, descriptor, name,
- 'JSObject*', args, inline=True)
- self.id = idPrefix + "id::" + self.descriptor.name
- def definition_body(self):
- return """
-
- /* aGlobal and aReceiver are usually the same, but they can be different
- too. For example a sandbox often has an xray wrapper for a window as the
- prototype of the sandbox's global. In that case aReceiver is the xray
- wrapper and aGlobal is the sandbox's global.
- */
-
- /* Make sure our global is sane. Hopefully we can remove this sometime */
- if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) {
- return NULL;
- }
- /* Check to see whether the interface objects are already installed */
- JSObject** protoOrIfaceArray = GetProtoOrIfaceArray(aGlobal);
- JSObject* cachedObject = protoOrIfaceArray[%s];
- if (!cachedObject) {
- protoOrIfaceArray[%s] = cachedObject = CreateInterfaceObjects(aCx, aGlobal, aReceiver);
- }
-
- /* cachedObject might _still_ be null, but that's OK */
- return cachedObject;""" % (self.id, self.id)
-
-class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
- """
- A method for getting the interface prototype object.
- """
- def __init__(self, descriptor):
- CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject",
- "prototypes::")
- def definition_body(self):
- return """
- /* Get the interface prototype object for this class. This will create the
- object as needed. */""" + CGGetPerInterfaceObject.definition_body(self)
-
-class CGGetConstructorObjectMethod(CGGetPerInterfaceObject):
- """
- A method for getting the interface constructor object.
- """
- def __init__(self, descriptor):
- CGGetPerInterfaceObject.__init__(self, descriptor, "GetConstructorObject",
- "constructors::")
- def definition_body(self):
- return """
- /* Get the interface object for this class. This will create the object as
- needed. */""" + CGGetPerInterfaceObject.definition_body(self)
-
-def CheckPref(descriptor, globalName, varName, retval, wrapperCache = None):
- """
- Check whether bindings should be enabled for this descriptor. If not, set
- varName to false and return retval.
- """
- if not descriptor.prefable:
- return ""
-
- if wrapperCache:
- wrapperCache = " %s->ClearIsDOMBinding();\n" % (wrapperCache)
- else:
- wrapperCache = ""
-
- failureCode = (" %s = false;\n" +
- " return %s;") % (varName, retval)
- return """
- {
- XPCWrappedNativeScope* scope =
- XPCWrappedNativeScope::FindInJSObjectScope(aCx, %s);
- if (!scope) {
-%s
- }
-
- if (!scope->ExperimentalBindingsEnabled()) {
-%s%s
- }
- }
-""" % (globalName, failureCode, wrapperCache, failureCode)
-
-class CGDefineDOMInterfaceMethod(CGAbstractMethod):
- """
- A method for resolve hooks to try to lazily define the interface object for
- a given interface.
- """
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aReceiver'),
- Argument('bool*', 'aEnabled')]
- CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'bool', args)
-
- def declare(self):
- if self.descriptor.workers:
- return ''
- return CGAbstractMethod.declare(self)
-
- def define(self):
- if self.descriptor.workers:
- return ''
- return CGAbstractMethod.define(self)
-
- def definition_body(self):
- if self.descriptor.interface.hasInterfacePrototypeObject():
- # We depend on GetProtoObject defining an interface constructor
- # object as needed.
- getter = "GetProtoObject"
- else:
- getter = "GetConstructorObject"
-
- return (" JSObject* global = JS_GetGlobalForObject(aCx, aReceiver);\n" +
- CheckPref(self.descriptor, "global", "*aEnabled", "false") +
- """
- *aEnabled = true;
- return !!%s(aCx, global, aReceiver);""" % (getter))
-
-class CGPrefEnabled(CGAbstractMethod):
- """
- A method for testing whether the preference controlling this
- interface is enabled. When it's not, the interface should not be
- visible on the global.
- """
- def __init__(self, descriptor):
- CGAbstractMethod.__init__(self, descriptor, 'PrefEnabled', 'bool', [])
-
- def declare(self):
- return CGAbstractMethod.declare(self)
-
- def define(self):
- return CGAbstractMethod.define(self)
-
- def definition_body(self):
- return " return %s::PrefEnabled();" % self.descriptor.nativeType
-
-class CGIsMethod(CGAbstractMethod):
- def __init__(self, descriptor):
- args = [Argument('JSObject*', 'obj')]
- CGAbstractMethod.__init__(self, descriptor, 'Is', 'bool', args)
-
- def definition_body(self):
- # Non-proxy implementation would check
- # js::GetObjectJSClass(obj) == &Class.mBase
- return """ return IsProxy(obj);"""
-
-def CreateBindingJSObject(descriptor, parent):
- if descriptor.proxy:
- create = """ JSObject *obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(),
- JS::PrivateValue(aObject), proto, %s);
- if (!obj) {
- return NULL;
- }
-
-"""
- else:
- create = """ JSObject* obj = JS_NewObject(aCx, &Class.mBase, proto, %s);
- if (!obj) {
- return NULL;
- }
-
- js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject));
-"""
- return create % parent
-
-class CGWrapWithCacheMethod(CGAbstractMethod):
- def __init__(self, descriptor):
- assert descriptor.interface.hasInterfacePrototypeObject()
- args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
- Argument(descriptor.nativeType + '*', 'aObject'),
- Argument('nsWrapperCache*', 'aCache'),
- Argument('bool*', 'aTriedToWrap')]
- CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
-
- def definition_body(self):
- if self.descriptor.workers:
- return """ *aTriedToWrap = true;
- return aObject->GetJSObject();"""
-
- return """ *aTriedToWrap = true;
-
- JSObject* parent = WrapNativeParent(aCx, aScope, aObject->GetParentObject());
- if (!parent) {
- return NULL;
- }
-
- JSAutoCompartment ac(aCx, parent);
- JSObject* global = JS_GetGlobalForObject(aCx, parent);
-%s
- JSObject* proto = GetProtoObject(aCx, global, global);
- if (!proto) {
- return NULL;
- }
-
-%s
- NS_ADDREF(aObject);
-
- aCache->SetWrapper(obj);
-
- return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"),
- CreateBindingJSObject(self.descriptor, "parent"))
-
-class CGWrapMethod(CGAbstractMethod):
- def __init__(self, descriptor):
- # XXX can we wrap if we don't have an interface prototype object?
- assert descriptor.interface.hasInterfacePrototypeObject()
- args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
- Argument('T*', 'aObject'), Argument('bool*', 'aTriedToWrap')]
- CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args, inline=True, templateArgs=["class T"])
-
- def definition_body(self):
- return " return Wrap(aCx, aScope, aObject, aObject, aTriedToWrap);"
-
-class CGWrapNonWrapperCacheMethod(CGAbstractMethod):
- def __init__(self, descriptor):
- # XXX can we wrap if we don't have an interface prototype object?
- assert descriptor.interface.hasInterfacePrototypeObject()
- args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
- Argument(descriptor.nativeType + '*', 'aObject')]
- CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
-
- def definition_body(self):
- return """
- JSObject* global = JS_GetGlobalForObject(aCx, aScope);
- JSObject* proto = GetProtoObject(aCx, global, global);
- if (!proto) {
- return NULL;
- }
-
-%s
- NS_ADDREF(aObject);
-
- return obj;""" % CreateBindingJSObject(self.descriptor, "global")
-
-builtinNames = {
- IDLType.Tags.bool: 'bool',
- IDLType.Tags.int8: 'int8_t',
- IDLType.Tags.int16: 'int16_t',
- IDLType.Tags.int32: 'int32_t',
- IDLType.Tags.int64: 'int64_t',
- IDLType.Tags.uint8: 'uint8_t',
- IDLType.Tags.uint16: 'uint16_t',
- IDLType.Tags.uint32: 'uint32_t',
- IDLType.Tags.uint64: 'uint64_t',
- IDLType.Tags.float: 'float',
- IDLType.Tags.double: 'double'
-}
-
-numericTags = [
- IDLType.Tags.int8, IDLType.Tags.uint8,
- IDLType.Tags.int16, IDLType.Tags.uint16,
- IDLType.Tags.int32, IDLType.Tags.uint32,
- IDLType.Tags.int64, IDLType.Tags.uint64,
- IDLType.Tags.float, IDLType.Tags.double
- ]
-
-class CastableObjectUnwrapper():
- """
- A class for unwrapping an object named by the "source" argument
- based on the passed-in descriptor and storing it in a variable
- called by the name in the "target" argument.
-
- codeOnFailure is the code to run if unwrapping fails.
- """
- def __init__(self, descriptor, source, target, codeOnFailure):
- assert descriptor.castable
-
- self.substitution = { "type" : descriptor.nativeType,
- "protoID" : "prototypes::id::" + descriptor.name,
- "source" : source,
- "target" : target,
- "codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure), 4).define() }
- if descriptor.hasXPConnectImpls:
- # We don't use xpc_qsUnwrapThis because it will always throw on
- # unwrap failure, whereas we want to control whether we throw or
- # not.
- self.substitution["codeOnFailure"] = CGIndenter(CGGeneric(string.Template(
- "${type} *objPtr;\n"
- "xpc_qsSelfRef objRef;\n"
- "JS::Value val = JS::ObjectValue(*${source});\n"
- "nsresult rv = xpc_qsUnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n"
- "if (NS_FAILED(rv)) {\n"
- "${codeOnFailure}\n"
- "}\n"
- "// We should be castable!\n"
- "MOZ_ASSERT(!objRef.ptr);\n"
- "// We should have an object, too!\n"
- "MOZ_ASSERT(objPtr);\n"
- "${target} = objPtr;").substitute(self.substitution)), 4).define()
-
- def __str__(self):
- return string.Template(
-"""{
- nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target});
- if (NS_FAILED(rv)) {
-${codeOnFailure}
- }
-}""").substitute(self.substitution)
-
-class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
- """
- As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails
- """
- def __init__(self, descriptor, source, target):
- CastableObjectUnwrapper.__init__(self, descriptor, source, target,
- "return Throw<%s>(cx, rv);" %
- toStringBool(not descriptor.workers))
-
-class CallbackObjectUnwrapper:
- """
- A class for unwrapping objects implemented in JS.
-
- |source| is the JSObject we want to use in native code.
- |target| is an nsCOMPtr of the appropriate type in which we store the result.
- """
- def __init__(self, descriptor, source, target, codeOnFailure=None):
- if codeOnFailure is None:
- codeOnFailure = ("return Throw<%s>(cx, rv);" %
- toStringBool(not descriptor.workers))
- self.descriptor = descriptor
- self.substitution = { "nativeType" : descriptor.nativeType,
- "source" : source,
- "target" : target,
- "codeOnFailure" : CGIndenter(CGGeneric(codeOnFailure)).define() }
-
- def __str__(self):
- if self.descriptor.workers:
- return string.Template(
- "${target} = ${source};"
- ).substitute(self.substitution)
-
- return string.Template(
- """nsresult rv;
-XPCCallContext ccx(JS_CALLER, cx);
-if (!ccx.IsValid()) {
- rv = NS_ERROR_XPC_BAD_CONVERT_JS;
-${codeOnFailure}
-}
-
-const nsIID& iid = NS_GET_IID(${nativeType});
-nsRefPtr<nsXPCWrappedJS> wrappedJS;
-rv = nsXPCWrappedJS::GetNewOrUsed(ccx, ${source}, iid,
- NULL, getter_AddRefs(wrappedJS));
-if (NS_FAILED(rv) || !wrappedJS) {
-${codeOnFailure}
-}
-
-// Use a temp nsCOMPtr for the null-check, because ${target} might be
-// OwningNonNull, not an nsCOMPtr.
-nsCOMPtr<${nativeType}> tmp = do_QueryObject(wrappedJS.get());
-if (!tmp) {
-${codeOnFailure}
-}
-${target} = tmp.forget();""").substitute(self.substitution)
-
-def dictionaryHasSequenceMember(dictionary):
- return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in
- dictionary.members) or
- (dictionary.parent and
- dictionaryHasSequenceMember(dictionary.parent)))
-
-def typeIsSequenceOrHasSequenceMember(type):
- if type.nullable():
- type = type.inner
- if type.isSequence():
- return True
- if type.isArray():
- elementType = type.inner
- return typeIsSequenceOrHasSequenceMember(elementType)
- if type.isDictionary():
- return dictionaryHasSequenceMember(type.inner)
- if type.isUnion():
- return any(typeIsSequenceOrHasSequenceMember(m.type) for m in
- type.flatMemberTypes)
- return False
-
-def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
- isDefinitelyObject=False,
- isMember=False,
- isOptional=False,
- invalidEnumValueFatal=True,
- defaultValue=None,
- treatNullAs="Default",
- treatUndefinedAs="Default",
- isEnforceRange=False,
- isClamp=False):
- """
- Get a template for converting a JS value to a native object based on the
- given type and descriptor. If failureCode is given, then we're actually
- testing whether we can convert the argument to the desired type. That
- means that failures to convert due to the JS value being the wrong type of
- value need to use failureCode instead of throwing exceptions. Failures to
- convert that are due to JS exceptions (from toString or valueOf methods) or
- out of memory conditions need to throw exceptions no matter what
- failureCode is.
-
- If isDefinitelyObject is True, that means we know the value
- isObject() and we have no need to recheck that.
-
- if isMember is True, we're being converted from a property of some
- JS object, not from an actual method argument, so we can't rely on
- our jsval being rooted or outliving us in any way. Any caller
- passing true needs to ensure that it is handled correctly in
- typeIsSequenceOrHasSequenceMember.
-
- If isOptional is true, then we are doing conversion of an optional
- argument with no default value.
-
- invalidEnumValueFatal controls whether an invalid enum value conversion
- attempt will throw (if true) or simply return without doing anything (if
- false).
-
- If defaultValue is not None, it's the IDL default value for this conversion
-
- If isEnforceRange is true, we're converting an integer and throwing if the
- value is out of range.
-
- If isClamp is true, we're converting an integer and clamping if the
- value is out of range.
-
- The return value from this function is a tuple consisting of four things:
-
- 1) A string representing the conversion code. This will have template
- substitution performed on it as follows:
-
- ${val} replaced by an expression for the JS::Value in question
- ${valPtr} is a pointer to the JS::Value in question
- ${holderName} replaced by the holder's name, if any
- ${declName} replaced by the declaration's name
- ${haveValue} replaced by an expression that evaluates to a boolean
- for whether we have a JS::Value. Only used when
- defaultValue is not None.
-
- 2) A CGThing representing the native C++ type we're converting to
- (declType). This is allowed to be None if the conversion code is
- supposed to be used as-is.
- 3) A CGThing representing the type of a "holder" (holderType) which will
- hold a possible reference to the C++ thing whose type we returned in #1,
- or None if no such holder is needed.
- 4) A boolean indicating whether the caller has to do optional-argument handling.
- This will only be true if isOptional is true and if the returned template
- expects both declType and holderType to be wrapped in Optional<>, with
- ${declName} and ${holderName} adjusted to point to the Value() of the
- Optional, and Construct() calls to be made on the Optional<>s as needed.
-
- ${declName} must be in scope before the generated code is entered.
-
- If holderType is not None then ${holderName} must be in scope
- before the generated code is entered.
- """
- # If we have a defaultValue then we're not actually optional for
- # purposes of what we need to be declared as.
- assert(defaultValue is None or not isOptional)
-
- # Also, we should not have a defaultValue if we know we're an object
- assert(not isDefinitelyObject or defaultValue is None)
-
- # Helper functions for dealing with failures due to the JS value being the
- # wrong type of value
- def onFailureNotAnObject(failureCode):
- return CGWrapper(CGGeneric(
- failureCode or
- 'return ThrowErrorMessage(cx, MSG_NOT_OBJECT);'), post="\n")
- def onFailureBadType(failureCode, typeName):
- return CGWrapper(CGGeneric(
- failureCode or
- 'return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s");' % typeName), post="\n")
-
- # A helper function for handling default values. Takes a template
- # body and the C++ code to set the default value and wraps the
- # given template body in handling for the default value.
- def handleDefault(template, setDefault):
- if defaultValue is None:
- return template
- return CGWrapper(
- CGIndenter(CGGeneric(template)),
- pre="if (${haveValue}) {\n",
- post=("\n"
- "} else {\n"
- "%s;\n"
- "}" %
- CGIndenter(CGGeneric(setDefault)).define())).define()
-
- # A helper function for handling null default values. Much like
- # handleDefault, but checks that the default value, if it exists, is null.
- def handleDefaultNull(template, codeToSetNull):
- if (defaultValue is not None and
- not isinstance(defaultValue, IDLNullValue)):
- raise TypeError("Can't handle non-null default value here")
- return handleDefault(template, codeToSetNull)
-
- # A helper function for wrapping up the template body for
- # possibly-nullable objecty stuff
- def wrapObjectTemplate(templateBody, isDefinitelyObject, type,
- codeToSetNull, failureCode=None):
- if not isDefinitelyObject:
- # Handle the non-object cases by wrapping up the whole
- # thing in an if cascade.
- templateBody = (
- "if (${val}.isObject()) {\n" +
- CGIndenter(CGGeneric(templateBody)).define() + "\n")
- if type.nullable():
- templateBody += (
- "} else if (${val}.isNullOrUndefined()) {\n"
- " %s;\n" % codeToSetNull)
- templateBody += (
- "} else {\n" +
- CGIndenter(onFailureNotAnObject(failureCode)).define() +
- "}")
- if type.nullable():
- templateBody = handleDefaultNull(templateBody, codeToSetNull)
- else:
- assert(defaultValue is None)
-
- return templateBody
-
- assert not (isEnforceRange and isClamp) # These are mutually exclusive
-
- if type.isArray():
- raise TypeError("Can't handle array arguments yet")
-
- if type.isSequence():
- assert not isEnforceRange and not isClamp
-
- if failureCode is not None:
- raise TypeError("Can't handle sequences when failureCode is not None")
- nullable = type.nullable();
- # Be very careful not to change "type": we need it later
- if nullable:
- elementType = type.inner.inner
- else:
- elementType = type.inner
-
- # We have to be careful with reallocation behavior for arrays. In
- # particular, if we have a sequence of elements which are themselves
- # sequences (so nsAutoTArrays) or have sequences as members, we have a
- # problem. In that case, resizing the outermost nsAutoTarray to the
- # right size will memmove its elements, but nsAutoTArrays are not
- # memmovable and hence will end up with pointers to bogus memory, which
- # is bad. To deal with this, we disallow sequences, arrays,
- # dictionaries, and unions which contain sequences as sequence item
- # types. If WebIDL ever adds another container type, we'd have to
- # disallow it as well.
- if typeIsSequenceOrHasSequenceMember(elementType):
- raise TypeError("Can't handle a sequence containing another "
- "sequence as an element or member of an element. "
- "See the big comment explaining why.\n%s" %
- str(type.location))
-
- (elementTemplate, elementDeclType,
- elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate(
- elementType, descriptorProvider, isMember=True)
- if dealWithOptional:
- raise TypeError("Shouldn't have optional things in sequences")
- if elementHolderType is not None:
- raise TypeError("Shouldn't need holders for sequences")
-
- typeName = CGWrapper(elementDeclType, pre="Sequence< ", post=" >")
- if nullable:
- typeName = CGWrapper(typeName, pre="Nullable< ", post=" >")
- arrayRef = "${declName}.Value()"
- else:
- arrayRef = "${declName}"
- # If we're optional, the const will come from the Optional
- mutableTypeName = typeName
- if not isOptional:
- typeName = CGWrapper(typeName, pre="const ")
-
- templateBody = ("""JSObject* seq = &${val}.toObject();\n
-if (!IsArrayLike(cx, seq)) {
- return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);
-}
-uint32_t length;
-// JS_GetArrayLength actually works on all objects
-if (!JS_GetArrayLength(cx, seq, &length)) {
- return false;
-}
-Sequence< %s > &arr = const_cast< Sequence< %s >& >(%s);
-if (!arr.SetCapacity(length)) {
- return Throw<%s>(cx, NS_ERROR_OUT_OF_MEMORY);
-}
-for (uint32_t i = 0; i < length; ++i) {
- jsval temp;
- if (!JS_GetElement(cx, seq, i, &temp)) {
- return false;
- }
-""" % (toStringBool(descriptorProvider.workers),
- elementDeclType.define(),
- elementDeclType.define(),
- arrayRef,
- toStringBool(descriptorProvider.workers)))
-
- templateBody += CGIndenter(CGGeneric(
- string.Template(elementTemplate).substitute(
- {
- "val" : "temp",
- "valPtr": "&temp",
- "declName" : "(*arr.AppendElement())"
- }
- ))).define()
-
- templateBody += "\n}"
- templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
- type,
- "const_cast< %s & >(${declName}).SetNull()" % mutableTypeName.define())
- return (templateBody, typeName, None, isOptional)
-
- if type.isUnion():
- if isMember:
- raise TypeError("Can't handle unions as members, we have a "
- "holderType")
- nullable = type.nullable();
- if nullable:
- type = type.inner
-
- assert(defaultValue is None or
- (isinstance(defaultValue, IDLNullValue) and nullable))
-
- unionArgumentObj = "${holderName}"
- if isOptional or nullable:
- unionArgumentObj += ".ref()"
-
- memberTypes = type.flatMemberTypes
- names = []
-
- interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes)
- if len(interfaceMemberTypes) > 0:
- interfaceObject = []
- for memberType in interfaceMemberTypes:
- if type.isGeckoInterface():
- name = memberType.inner.identifier.name
- else:
- name = memberType.name
- interfaceObject.append(CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext" % (unionArgumentObj, name)))
- names.append(name)
- interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"), pre="done = ", post=";\n", reindent=True)
- else:
- interfaceObject = None
-
- arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes)
- if len(arrayObjectMemberTypes) > 0:
- assert len(arrayObjectMemberTypes) == 1
- memberType = arrayObjectMemberTypes[0]
- name = memberType.name
- arrayObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
- # XXX Now we're supposed to check for an array or a platform object
- # that supports indexed properties... skip that last for now. It's a
- # bit of a pain.
- arrayObject = CGWrapper(CGIndenter(arrayObject),
- pre="if (IsArrayLike(cx, &argObj)) {\n",
- post="}")
- names.append(name)
- else:
- arrayObject = None
-
- dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes)
- if len(dateObjectMemberTypes) > 0:
- assert len(dateObjectMemberTypes) == 1
- memberType = dateObjectMemberTypes[0]
- name = memberType.name
- dateObject = CGGeneric("%s.SetTo%s(cx, ${val}, ${valPtr});\n"
- "done = true;" % (unionArgumentObj, name))
- dateObject = CGWrapper(CGIndenter(dateObject),
- pre="if (JS_ObjectIsDate(cx, &argObj)) {\n",
- post="\n}")
- names.append(name)
- else:
- dateObject = None
-
- callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes)
- if len(callbackMemberTypes) > 0:
- assert len(callbackMemberTypes) == 1
- memberType = callbackMemberTypes[0]
- name = memberType.name
- callbackObject = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
- names.append(name)
- else:
- callbackObject = None
-
- dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes)
- if len(dictionaryMemberTypes) > 0:
- raise TypeError("No support for unwrapping dictionaries as member "
- "of a union")
- else:
- dictionaryObject = None
-
- if callbackObject or dictionaryObject:
- nonPlatformObject = CGList([callbackObject, dictionaryObject], "\n")
- nonPlatformObject = CGWrapper(CGIndenter(nonPlatformObject),
- pre="if (!IsPlatformObject(cx, &argObj)) {\n",
- post="\n}")
- else:
- nonPlatformObject = None
-
- objectMemberTypes = filter(lambda t: t.isObject(), memberTypes)
- if len(objectMemberTypes) > 0:
- object = CGGeneric("%s.SetToObject(&argObj);\n"
- "done = true;" % unionArgumentObj)
- else:
- object = None
-
- hasObjectTypes = interfaceObject or arrayObject or dateObject or nonPlatformObject or object
- if hasObjectTypes:
- # If we try more specific object types first then we need to check
- # whether that succeeded before converting to object.
- if object and (interfaceObject or arrayObject or dateObject or nonPlatformObject):
- object = CGWrapper(CGIndenter(object), pre="if (!done) {\n",
- post=("\n}"))
-
- if arrayObject or dateObject or nonPlatformObject:
- # An object can be both an array object and not a platform
- # object, but we shouldn't have both in the union's members
- # because they are not distinguishable.
- assert not (arrayObject and nonPlatformObject)
- templateBody = CGList([arrayObject, dateObject, nonPlatformObject], " else ")
- else:
- templateBody = None
- if interfaceObject:
- if templateBody:
- templateBody = CGList([templateBody, object], "\n")
- templateBody = CGWrapper(CGIndenter(templateBody),
- pre="if (!done) {\n", post=("\n}"))
- templateBody = CGList([interfaceObject, templateBody], "\n")
- else:
- templateBody = CGList([templateBody, object], "\n")
-
- if any([arrayObject, dateObject, nonPlatformObject, object]):
- templateBody.prepend(CGGeneric("JSObject& argObj = ${val}.toObject();"))
- templateBody = CGWrapper(CGIndenter(templateBody),
- pre="if (${val}.isObject()) {\n",
- post="\n}")
- else:
- templateBody = CGGeneric()
-
- otherMemberTypes = filter(lambda t: t.isString() or t.isEnum(),
- memberTypes)
- otherMemberTypes.extend(t for t in memberTypes if t.isPrimitive())
- if len(otherMemberTypes) > 0:
- assert len(otherMemberTypes) == 1
- memberType = otherMemberTypes[0]
- if memberType.isEnum():
- name = memberType.inner.identifier.name
- else:
- name = memberType.name
- other = CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${valPtr}, tryNext)) || !tryNext;" % (unionArgumentObj, name))
- names.append(name)
- if hasObjectTypes:
- other = CGWrapper(CGIndenter(other), "{\n", post="\n}")
- if object:
- join = " else "
- else:
- other = CGWrapper(other, pre="if (!done) ")
- join = "\n"
- templateBody = CGList([templateBody, other], join)
- else:
- other = None
-
- templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n")
- throw = CGGeneric("if (failed) {\n"
- " return false;\n"
- "}\n"
- "if (!done) {\n"
- " return ThrowErrorMessage(cx, MSG_NOT_IN_UNION, \"%s\");\n"
- "}" % ", ".join(names))
- templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw], "\n")), pre="{\n", post="\n}")
-
- typeName = type.name
- argumentTypeName = typeName + "Argument"
- if nullable:
- typeName = "Nullable<" + typeName + " >"
- if isOptional:
- nonConstDecl = "const_cast<Optional<" + typeName + " >& >(${declName})"
- else:
- nonConstDecl = "const_cast<" + typeName + "& >(${declName})"
- typeName = "const " + typeName
-
- def handleNull(templateBody, setToNullVar, extraConditionForNull=""):
- null = CGGeneric("if (%s${val}.isNullOrUndefined()) {\n"
- " %s.SetNull();\n"
- "}" % (extraConditionForNull, setToNullVar))
- templateBody = CGWrapper(CGIndenter(templateBody), pre="{\n", post="\n}")
- return CGList([null, templateBody], " else ")
-
- if type.hasNullableType:
- templateBody = handleNull(templateBody, unionArgumentObj)
-
- declType = CGGeneric(typeName)
- holderType = CGGeneric(argumentTypeName)
- if isOptional:
- mutableDecl = nonConstDecl + ".Value()"
- declType = CGWrapper(declType, pre="const Optional<", post=" >")
- holderType = CGWrapper(holderType, pre="Maybe<", post=" >")
- constructDecl = CGGeneric(nonConstDecl + ".Construct();")
- if nullable:
- constructHolder = CGGeneric("${holderName}.construct(%s.SetValue());" % mutableDecl)
- else:
- constructHolder = CGGeneric("${holderName}.construct(${declName}.Value());")
- else:
- mutableDecl = nonConstDecl
- constructDecl = None
- if nullable:
- holderType = CGWrapper(holderType, pre="Maybe<", post=" >")
- constructHolder = CGGeneric("${holderName}.construct(%s.SetValue());" % mutableDecl)
- else:
- constructHolder = CGWrapper(holderType, post=" ${holderName}(${declName});")
- holderType = None
-
- templateBody = CGList([constructHolder, templateBody], "\n")
- if nullable:
- if defaultValue:
- assert(isinstance(defaultValue, IDLNullValue))
- valueMissing = "!(${haveValue}) || "
- else:
- valueMissing = ""
- templateBody = handleNull(templateBody, mutableDecl,
- extraConditionForNull=valueMissing)
- templateBody = CGList([constructDecl, templateBody], "\n")
-
- return templateBody.define(), declType, holderType, False
-
- if type.isGeckoInterface():
- assert not isEnforceRange and not isClamp
-
- descriptor = descriptorProvider.getDescriptor(
- type.unroll().inner.identifier.name)
- # This is an interface that we implement as a concrete class
- # or an XPCOM interface.
-
- # Allow null pointers for nullable types and old-binding classes
- argIsPointer = type.nullable() or type.unroll().inner.isExternal()
-
- # Sequences and non-worker callbacks have to hold a strong ref to the
- # thing being passed down.
- forceOwningType = (descriptor.interface.isCallback() and
- not descriptor.workers) or isMember
-
- typeName = descriptor.nativeType
- typePtr = typeName + "*"
-
- # Compute a few things:
- # - declType is the type we want to return as the first element of our
- # tuple.
- # - holderType is the type we want to return as the third element
- # of our tuple.
-
- # Set up some sensible defaults for these things insofar as we can.
- holderType = None
- if argIsPointer:
- if forceOwningType:
- declType = "nsRefPtr<" + typeName + ">"
- else:
- declType = typePtr
- else:
- if forceOwningType:
- declType = "OwningNonNull<" + typeName + ">"
- else:
- declType = "NonNull<" + typeName + ">"
-
- templateBody = ""
- if descriptor.castable:
- if descriptor.prefable:
- raise TypeError("We don't support prefable castable object "
- "arguments (like %s), because we don't know "
- "how to handle them being preffed off" %
- descriptor.interface.identifier.name)
- if descriptor.interface.isConsequential():
- raise TypeError("Consequential interface %s being used as an "
- "argument but flagged as castable" %
- descriptor.interface.identifier.name)
- if failureCode is not None:
- templateBody += str(CastableObjectUnwrapper(
- descriptor,
- "&${val}.toObject()",
- "${declName}",
- failureCode))
- else:
- templateBody += str(FailureFatalCastableObjectUnwrapper(
- descriptor,
- "&${val}.toObject()",
- "${declName}"))
- elif descriptor.interface.isCallback():
- templateBody += str(CallbackObjectUnwrapper(
- descriptor,
- "&${val}.toObject()",
- "${declName}",
- codeOnFailure=failureCode))
- elif descriptor.workers:
- templateBody += "${declName} = &${val}.toObject();"
- else:
- # Either external, or new-binding non-castable. We always have a
- # holder for these, because we don't actually know whether we have
- # to addref when unwrapping or not. So we just pass an
- # getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release
- # it'll put a non-null pointer in there.
- if forceOwningType:
- # Don't return a holderType in this case; our declName
- # will just own stuff.
- templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n"
- else:
- holderType = "nsRefPtr<" + typeName + ">"
- templateBody += (
- "jsval tmpVal = ${val};\n" +
- typePtr + " tmp;\n"
- "if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n")
- templateBody += CGIndenter(onFailureBadType(failureCode,
- descriptor.interface.identifier.name)).define()
- templateBody += ("}\n"
- "MOZ_ASSERT(tmp);\n")
-
- if not isDefinitelyObject:
- # Our tmpVal will go out of scope, so we can't rely on it
- # for rooting
- templateBody += (
- "if (tmpVal != ${val} && !${holderName}) {\n"
- " // We have to have a strong ref, because we got this off\n"
- " // some random object that might get GCed\n"
- " ${holderName} = tmp;\n"
- "}\n")
-
- # And store our tmp, before it goes out of scope.
- templateBody += "${declName} = tmp;"
-
- templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
- type, "${declName} = NULL",
- failureCode)
-
- declType = CGGeneric(declType)
- if holderType is not None:
- holderType = CGGeneric(holderType)
- return (templateBody, declType, holderType, isOptional)
-
- if type.isSpiderMonkeyInterface():
- assert not isEnforceRange and not isClamp
- if isMember:
- raise TypeError("Can't handle member arraybuffers or "
- "arraybuffer views because making sure all the "
- "objects are properly rooted is hard")
- name = type.name
- # By default, we use a Maybe<> to hold our typed array. And in the optional
- # non-nullable case we want to pass Optional<TypedArray> to consumers, not
- # Optional<NonNull<TypedArray> >, so jump though some hoops to do that.
- holderType = "Maybe<%s>" % name
- constructLoc = "${holderName}"
- constructMethod = "construct"
- constructInternal = "ref"
- if type.nullable():
- if isOptional:
- declType = "const Optional<" + name + "*>"
- else:
- declType = name + "*"
- else:
- if isOptional:
- declType = "const Optional<" + name + ">"
- # We don't need a holder in this case
- holderType = None
- constructLoc = "(const_cast<Optional<" + name + ">& >(${declName}))"
- constructMethod = "Construct"
- constructInternal = "Value"
- else:
- declType = "NonNull<" + name + ">"
- template = (
- "%s.%s(cx, &${val}.toObject());\n"
- "if (!%s.%s().inited()) {\n"
- "%s" # No newline here because onFailureBadType() handles that
- "}\n" %
- (constructLoc, constructMethod, constructLoc, constructInternal,
- CGIndenter(onFailureBadType(failureCode, type.name)).define()))
- nullableTarget = ""
- if type.nullable():
- if isOptional:
- mutableDecl = "(const_cast<Optional<" + name + "*>& >(${declName}))"
- template += "%s.Construct();\n" % mutableDecl
- nullableTarget = "%s.Value()" % mutableDecl
- else:
- nullableTarget = "${declName}"
- template += "%s = ${holderName}.addr();" % nullableTarget
- elif not isOptional:
- template += "${declName} = ${holderName}.addr();"
- template = wrapObjectTemplate(template, isDefinitelyObject, type,
- "%s = NULL" % nullableTarget,
- failureCode)
-
- if holderType is not None:
- holderType = CGGeneric(holderType)
- # We handle all the optional stuff ourselves; no need for caller to do it.
- return (template, CGGeneric(declType), holderType, False)
-
- if type.isString():
- assert not isEnforceRange and not isClamp
-
- treatAs = {
- "Default": "eStringify",
- "EmptyString": "eEmpty",
- "Null": "eNull"
- }
- if type.nullable():
- # For nullable strings null becomes a null string.
- treatNullAs = "Null"
- # For nullable strings undefined becomes a null string unless
- # specified otherwise.
- if treatUndefinedAs == "Default":
- treatUndefinedAs = "Null"
- nullBehavior = treatAs[treatNullAs]
- if treatUndefinedAs == "Missing":
- raise TypeError("We don't support [TreatUndefinedAs=Missing]")
- undefinedBehavior = treatAs[treatUndefinedAs]
-
- def getConversionCode(varName):
- conversionCode = (
- "if (!ConvertJSValueToString(cx, ${val}, ${valPtr}, %s, %s, %s)) {\n"
- " return false;\n"
- "}" % (nullBehavior, undefinedBehavior, varName))
- if defaultValue is None:
- return conversionCode
-
- if isinstance(defaultValue, IDLNullValue):
- assert(type.nullable())
- return handleDefault(conversionCode,
- "%s.SetNull()" % varName)
- return handleDefault(
- conversionCode,
- ("static const PRUnichar data[] = { %s };\n"
- "%s.SetData(data, ArrayLength(data) - 1)" %
- (", ".join(["'" + char + "'" for char in defaultValue.value] + ["0"]),
- varName)))
-
- if isMember:
- # We have to make a copy, because our jsval may well not
- # live as long as our string needs to.
- declType = CGGeneric("nsString")
- return (
- "{\n"
- " FakeDependentString str;\n"
- "%s\n"
- " ${declName} = str;\n"
- "}\n" % CGIndenter(CGGeneric(getConversionCode("str"))).define(),
- declType, None, isOptional)
-
- if isOptional:
- declType = "Optional<nsAString>"
- else:
- declType = "NonNull<nsAString>"
-
- return (
- "%s\n"
- "const_cast<%s&>(${declName}) = &${holderName};" %
- (getConversionCode("${holderName}"), declType),
- CGGeneric("const " + declType), CGGeneric("FakeDependentString"),
- # No need to deal with Optional here; we have handled it already
- False)
-
- if type.isEnum():
- assert not isEnforceRange and not isClamp
-
- if type.nullable():
- raise TypeError("We don't support nullable enumerated arguments "
- "yet")
- enum = type.inner.identifier.name
- if invalidEnumValueFatal:
- handleInvalidEnumValueCode = " MOZ_ASSERT(index >= 0);\n"
- else:
- handleInvalidEnumValueCode = (
- " if (index < 0) {\n"
- " return true;\n"
- " }\n")
-
- template = (
- "{\n"
- " bool ok;\n"
- " int index = FindEnumStringIndex<%(invalidEnumValueFatal)s>(cx, ${val}, %(values)s, \"%(enumtype)s\", &ok);\n"
- " if (!ok) {\n"
- " return false;\n"
- " }\n"
- "%(handleInvalidEnumValueCode)s"
- " ${declName} = static_cast<%(enumtype)s>(index);\n"
- "}" % { "enumtype" : enum,
- "values" : enum + "Values::strings",
- "invalidEnumValueFatal" : toStringBool(invalidEnumValueFatal),
- "handleInvalidEnumValueCode" : handleInvalidEnumValueCode })
-
- if defaultValue is not None:
- assert(defaultValue.type.tag() == IDLType.Tags.domstring)
- template = handleDefault(template,
- ("${declName} = %sValues::%s" %
- (enum,
- getEnumValueName(defaultValue.value))))
- return (template, CGGeneric(enum), None, isOptional)
-
- if type.isCallback():
- assert not isEnforceRange and not isClamp
-
- if isMember:
- raise TypeError("Can't handle member callbacks; need to sort out "
- "rooting issues")
- # XXXbz we're going to assume that callback types are always
- # nullable and always have [TreatNonCallableAsNull] for now.
- haveCallable = "${val}.isObject() && JS_ObjectIsCallable(cx, &${val}.toObject())"
- if defaultValue is not None:
- assert(isinstance(defaultValue, IDLNullValue))
- haveCallable = "${haveValue} && " + haveCallable
- return (
- "if (%s) {\n"
- " ${declName} = &${val}.toObject();\n"
- "} else {\n"
- " ${declName} = NULL;\n"
- "}" % haveCallable,
- CGGeneric("JSObject*"), None, isOptional)
-
- if type.isAny():
- assert not isEnforceRange and not isClamp
-
- if isMember:
- raise TypeError("Can't handle member 'any'; need to sort out "
- "rooting issues")
- templateBody = "${declName} = ${val};"
- templateBody = handleDefaultNull(templateBody,
- "${declName} = JS::NullValue()")
- return (templateBody, CGGeneric("JS::Value"), None, isOptional)
-
- if type.isObject():
- assert not isEnforceRange and not isClamp
-
- if isMember:
- raise TypeError("Can't handle member 'object'; need to sort out "
- "rooting issues")
- template = wrapObjectTemplate("${declName} = &${val}.toObject();",
- isDefinitelyObject, type,
- "${declName} = NULL",
- failureCode)
- if type.nullable():
- declType = CGGeneric("JSObject*")
- else:
- declType = CGGeneric("NonNull<JSObject>")
- return (template, declType, None, isOptional)
-
- if type.isDictionary():
- if failureCode is not None:
- raise TypeError("Can't handle dictionaries when failureCode is not None")
- # There are no nullable dictionaries
- assert not type.nullable()
- # All optional dictionaries always have default values, so we
- # should be able to assume not isOptional here.
- assert not isOptional
-
- typeName = CGDictionary.makeDictionaryName(type.inner,
- descriptorProvider.workers)
- actualTypeName = typeName
- selfRef = "${declName}"
-
- declType = CGGeneric(actualTypeName)
-
- # If we're a member of something else, the const
- # will come from the Optional or our container.
- if not isMember:
- declType = CGWrapper(declType, pre="const ")
- selfRef = "const_cast<%s&>(%s)" % (typeName, selfRef)
-
- # We do manual default value handling here, because we
- # actually do want a jsval, and we only handle null anyway
- if defaultValue is not None:
- assert(isinstance(defaultValue, IDLNullValue))
- val = "(${haveValue}) ? ${val} : JSVAL_NULL"
- else:
- val = "${val}"
-
- template = ("if (!%s.Init(cx, %s)) {\n"
- " return false;\n"
- "}" % (selfRef, val))
-
- return (template, declType, None, False)
-
- if not type.isPrimitive():
- raise TypeError("Need conversion for argument type '%s'" % str(type))
-
- typeName = builtinNames[type.tag()]
-
- conversionBehavior = "eDefault"
- if isEnforceRange:
- conversionBehavior = "eEnforceRange"
- elif isClamp:
- conversionBehavior = "eClamp"
-
- if type.nullable():
- dataLoc = "${declName}.SetValue()"
- nullCondition = "${val}.isNullOrUndefined()"
- if defaultValue is not None and isinstance(defaultValue, IDLNullValue):
- nullCondition = "!(${haveValue}) || " + nullCondition
- template = (
- "if (%s) {\n"
- " ${declName}.SetNull();\n"
- "} else if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
- " return false;\n"
- "}" % (nullCondition, typeName, conversionBehavior, dataLoc))
- declType = CGGeneric("Nullable<" + typeName + ">")
- else:
- assert(defaultValue is None or
- not isinstance(defaultValue, IDLNullValue))
- dataLoc = "${declName}"
- template = (
- "if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n"
- " return false;\n"
- "}" % (typeName, conversionBehavior, dataLoc))
- declType = CGGeneric(typeName)
- if (defaultValue is not None and
- # We already handled IDLNullValue, so just deal with the other ones
- not isinstance(defaultValue, IDLNullValue)):
- tag = defaultValue.type.tag()
- if tag in numericTags:
- defaultStr = defaultValue.value
- else:
- assert(tag == IDLType.Tags.bool)
- defaultStr = toStringBool(defaultValue.value)
- template = CGWrapper(CGIndenter(CGGeneric(template)),
- pre="if (${haveValue}) {\n",
- post=("\n"
- "} else {\n"
- " %s = %s;\n"
- "}" % (dataLoc, defaultStr))).define()
-
- return (template, declType, None, isOptional)
-
-def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
- argcAndIndex=None):
- """
- Take a tuple as returned by getJSToNativeConversionTemplate and a set of
- replacements as required by the strings in such a tuple, and generate code
- to convert into stack C++ types.
-
- If argcAndIndex is not None it must be a dict that can be used to
- replace ${argc} and ${index}, where ${index} is the index of this
- argument (0-based) and ${argc} is the total number of arguments.
- """
- (templateBody, declType, holderType, dealWithOptional) = templateTuple
-
- if dealWithOptional and argcAndIndex is None:
- raise TypeError("Have to deal with optional things, but don't know how")
- if argcAndIndex is not None and declType is None:
- raise TypeError("Need to predeclare optional things, so they will be "
- "outside the check for big enough arg count!");
-
- result = CGList([], "\n")
- # Make a copy of "replacements" since we may be about to start modifying it
- replacements = dict(replacements)
- originalHolderName = replacements["holderName"]
- if holderType is not None:
- if dealWithOptional:
- replacements["holderName"] = (
- "const_cast< %s & >(%s.Value())" %
- (holderType.define(), originalHolderName))
- mutableHolderType = CGWrapper(holderType, pre="Optional< ", post=" >")
- holderType = CGWrapper(mutableHolderType, pre="const ")
- result.append(
- CGList([holderType, CGGeneric(" "),
- CGGeneric(originalHolderName),
- CGGeneric(";")]))
-
- originalDeclName = replacements["declName"]
- if declType is not None:
- if dealWithOptional:
- replacements["declName"] = (
- "const_cast< %s & >(%s.Value())" %
- (declType.define(), originalDeclName))
- mutableDeclType = CGWrapper(declType, pre="Optional< ", post=" >")
- declType = CGWrapper(mutableDeclType, pre="const ")
- result.append(
- CGList([declType, CGGeneric(" "),
- CGGeneric(originalDeclName),
- CGGeneric(";")]))
-
- conversion = CGGeneric(
- string.Template(templateBody).substitute(replacements)
- )
-
- if argcAndIndex is not None:
- if dealWithOptional:
- declConstruct = CGIndenter(
- CGGeneric("const_cast< %s &>(%s).Construct();" %
- (mutableDeclType.define(), originalDeclName)))
- if holderType is not None:
- holderConstruct = CGIndenter(
- CGGeneric("const_cast< %s &>(%s).Construct();" %
- (mutableHolderType.define(), originalHolderName)))
- else:
- holderConstruct = None
- else:
- declConstruct = None
- holderConstruct = None
-
- conversion = CGList(
- [CGGeneric(
- string.Template("if (${index} < ${argc}) {").substitute(
- argcAndIndex
- )),
- declConstruct,
- holderConstruct,
- CGIndenter(conversion),
- CGGeneric("}")],
- "\n")
-
- result.append(conversion)
- # Add an empty CGGeneric to get an extra newline after the argument
- # conversion.
- result.append(CGGeneric(""))
- return result;
-
-def convertConstIDLValueToJSVal(value):
- if isinstance(value, IDLNullValue):
- return "JSVAL_NULL"
- tag = value.type.tag()
- if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
- IDLType.Tags.uint16, IDLType.Tags.int32]:
- return "INT_TO_JSVAL(%s)" % (value.value)
- if tag == IDLType.Tags.uint32:
- return "UINT_TO_JSVAL(%s)" % (value.value)
- if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]:
- return "DOUBLE_TO_JSVAL(%s)" % (value.value)
- if tag == IDLType.Tags.bool:
- return "JSVAL_TRUE" if value.value else "JSVAL_FALSE"
- if tag in [IDLType.Tags.float, IDLType.Tags.double]:
- return "DOUBLE_TO_JSVAL(%s)" % (value.value)
- raise TypeError("Const value of unhandled type: " + value.type)
-
-class CGArgumentConverter(CGThing):
- """
- A class that takes an IDL argument object, its index in the
- argument list, and the argv and argc strings and generates code to
- unwrap the argument to the right native type.
- """
- def __init__(self, argument, index, argv, argc, descriptorProvider,
- invalidEnumValueFatal=True):
- CGThing.__init__(self)
- self.argument = argument
- if argument.variadic:
- raise TypeError("We don't support variadic arguments yet " +
- str(argument.location))
- assert(not argument.defaultValue or argument.optional)
-
- replacer = {
- "index" : index,
- "argc" : argc,
- "argv" : argv
- }
- self.replacementVariables = {
- "declName" : "arg%d" % index,
- "holderName" : ("arg%d" % index) + "_holder"
- }
- self.replacementVariables["val"] = string.Template(
- "${argv}[${index}]"
- ).substitute(replacer)
- self.replacementVariables["valPtr"] = (
- "&" + self.replacementVariables["val"])
- if argument.defaultValue:
- self.replacementVariables["haveValue"] = string.Template(
- "${index} < ${argc}").substitute(replacer)
- self.descriptorProvider = descriptorProvider
- if self.argument.optional and not self.argument.defaultValue:
- self.argcAndIndex = replacer
- else:
- self.argcAndIndex = None
- self.invalidEnumValueFatal = invalidEnumValueFatal
-
- def define(self):
- return instantiateJSToNativeConversionTemplate(
- getJSToNativeConversionTemplate(self.argument.type,
- self.descriptorProvider,
- isOptional=(self.argcAndIndex is not None),
- invalidEnumValueFatal=self.invalidEnumValueFatal,
- defaultValue=self.argument.defaultValue,
- treatNullAs=self.argument.treatNullAs,
- treatUndefinedAs=self.argument.treatUndefinedAs,
- isEnforceRange=self.argument.enforceRange,
- isClamp=self.argument.clamp),
- self.replacementVariables,
- self.argcAndIndex).define()
-
-def getWrapTemplateForType(type, descriptorProvider, result, successCode,
- isCreator):
- """
- Reflect a C++ value stored in "result", of IDL type "type" into JS. The
- "successCode" is the code to run once we have successfully done the
- conversion. The resulting string should be used with string.Template, it
- needs the following keys when substituting: jsvalPtr/jsvalRef/obj.
-
- Returns (templateString, infallibility of conversion template)
- """
- haveSuccessCode = successCode is not None
- if not haveSuccessCode:
- successCode = "return true;"
-
- def setValue(value, callWrapValue=False):
- """
- Returns the code to set the jsval to value. If "callWrapValue" is true
- JS_WrapValue will be called on the jsval.
- """
- if not callWrapValue:
- tail = successCode
- elif haveSuccessCode:
- tail = ("if (!JS_WrapValue(cx, ${jsvalPtr})) {\n" +
- " return false;\n" +
- "}\n" +
- successCode)
- else:
- tail = "return JS_WrapValue(cx, ${jsvalPtr});"
- return ("${jsvalRef} = %s;\n" +
- tail) % (value)
-
- def wrapAndSetPtr(wrapCall, failureCode=None):
- """
- Returns the code to set the jsval by calling "wrapCall". "failureCode"
- is the code to run if calling "wrapCall" fails
- """
- if failureCode is None:
- if not haveSuccessCode:
- return "return " + wrapCall + ";"
- failureCode = "return false;"
- str = ("if (!%s) {\n" +
- CGIndenter(CGGeneric(failureCode)).define() + "\n" +
- "}\n" +
- successCode) % (wrapCall)
- return str
-
- if type is None or type.isVoid():
- return (setValue("JSVAL_VOID"), True)
-
- if type.isArray():
- raise TypeError("Can't handle array return values yet")
-
- if type.isSequence():
- if type.nullable():
- # Nullable sequences are Nullable< nsTArray<T> >
- (recTemplate, recInfall) = getWrapTemplateForType(type.inner, descriptorProvider,
- "%s.Value()" % result, successCode,
- isCreator)
- return ("""
-if (%s.IsNull()) {
-%s
-}
-%s""" % (result, CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define(), recTemplate), recInfall)
-
- # Now do non-nullable sequences. We use setting the element
- # in the array as our succcess code because when we succeed in
- # wrapping that's what we should do.
- innerTemplate = wrapForType(
- type.inner, descriptorProvider,
- {
- 'result' : "%s[i]" % result,
- 'successCode': ("if (!JS_DefineElement(cx, returnArray, i, tmp,\n"
- " NULL, NULL, JSPROP_ENUMERATE)) {\n"
- " return false;\n"
- "}"),
- 'jsvalRef': "tmp",
- 'jsvalPtr': "&tmp",
- 'isCreator': isCreator
- }
- )
- innerTemplate = CGIndenter(CGGeneric(innerTemplate)).define()
- return (("""
-uint32_t length = %s.Length();
-JSObject *returnArray = JS_NewArrayObject(cx, length, NULL);
-if (!returnArray) {
- return false;
-}
-jsval tmp;
-for (uint32_t i = 0; i < length; ++i) {
-%s
-}\n""" % (result, innerTemplate)) + setValue("JS::ObjectValue(*returnArray)"), False)
-
- if type.isGeckoInterface():
- descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name)
- if type.nullable():
- wrappingCode = ("if (!%s) {\n" % (result) +
- CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
- "}\n")
- else:
- wrappingCode = ""
- if (not descriptor.interface.isExternal() and
- not descriptor.interface.isCallback()):
- if descriptor.wrapperCache:
- wrapMethod = "WrapNewBindingObject"
- else:
- if not isCreator:
- raise MethodNotCreatorError(descriptor.interface.identifier.name)
- wrapMethod = "WrapNewBindingNonWrapperCachedObject"
- wrap = "%s(cx, ${obj}, %s, ${jsvalPtr})" % (wrapMethod, result)
- # We don't support prefable stuff in workers.
- assert(not descriptor.prefable or not descriptor.workers)
- if not descriptor.prefable:
- # Non-prefable bindings can only fail to wrap as a new-binding object
- # if they already threw an exception. Same thing for
- # non-prefable bindings.
- failed = ("MOZ_ASSERT(JS_IsExceptionPending(cx));\n" +
- "return false;")
- else:
- if descriptor.notflattened:
- raise TypeError("%s is prefable but not flattened; "
- "fallback won't work correctly" %
- descriptor.interface.identifier.name)
- # Try old-style wrapping for bindings which might be preffed off.
- failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalPtr})" % result)
- wrappingCode += wrapAndSetPtr(wrap, failed)
- else:
- if descriptor.notflattened:
- getIID = "&NS_GET_IID(%s), " % descriptor.nativeType
- else:
- getIID = ""
- wrap = "WrapObject(cx, ${obj}, %s, %s${jsvalPtr})" % (result, getIID)
- wrappingCode += wrapAndSetPtr(wrap)
- return (wrappingCode, False)
-
- if type.isString():
- if type.nullable():
- return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalPtr})" % result), False)
- else:
- return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalPtr})" % result), False)
-
- if type.isEnum():
- if type.nullable():
- raise TypeError("We don't support nullable enumerated return types "
- "yet")
- return ("""MOZ_ASSERT(uint32_t(%(result)s) < ArrayLength(%(strings)s));
-JSString* %(resultStr)s = JS_NewStringCopyN(cx, %(strings)s[uint32_t(%(result)s)].value, %(strings)s[uint32_t(%(result)s)].length);
-if (!%(resultStr)s) {
- return false;
-}
-""" % { "result" : result,
- "resultStr" : result + "_str",
- "strings" : type.inner.identifier.name + "Values::strings" } +
- setValue("JS::StringValue(%s_str)" % result), False)
-
- if type.isCallback():
- assert not type.isInterface()
- # XXXbz we're going to assume that callback types are always
- # nullable and always have [TreatNonCallableAsNull] for now.
- # See comments in WrapNewBindingObject explaining why we need
- # to wrap here.
- # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
- return (setValue("JS::ObjectOrNullValue(%s)" % result, True), False)
-
- if type.tag() == IDLType.Tags.any:
- # See comments in WrapNewBindingObject explaining why we need
- # to wrap here.
- # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
- return (setValue(result, True), False)
-
- if type.isObject() or type.isSpiderMonkeyInterface():
- # See comments in WrapNewBindingObject explaining why we need
- # to wrap here.
- if type.nullable():
- toValue = "JS::ObjectOrNullValue(%s)"
- else:
- toValue = "JS::ObjectValue(*%s)"
- # NB: setValue(..., True) calls JS_WrapValue(), so is fallible
- return (setValue(toValue % result, True), False)
-
- if not type.isPrimitive():
- raise TypeError("Need to learn to wrap %s" % type)
-
- if type.nullable():
- (recTemplate, recInfal) = getWrapTemplateForType(type.inner, descriptorProvider,
- "%s.Value()" % result, successCode,
- isCreator)
- return ("if (%s.IsNull()) {\n" % result +
- CGIndenter(CGGeneric(setValue("JSVAL_NULL"))).define() + "\n" +
- "}\n" + recTemplate, recInfal)
-
- tag = type.tag()
-
- if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16,
- IDLType.Tags.uint16, IDLType.Tags.int32]:
- return (setValue("INT_TO_JSVAL(int32_t(%s))" % result), True)
-
- elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, IDLType.Tags.float,
- IDLType.Tags.double]:
- # XXXbz will cast to double do the "even significand" thing that webidl
- # calls for for 64-bit ints? Do we care?
- return (setValue("JS_NumberValue(double(%s))" % result), True)
-
- elif tag == IDLType.Tags.uint32:
- return (setValue("UINT_TO_JSVAL(%s)" % result), True)
-
- elif tag == IDLType.Tags.bool:
- return (setValue("BOOLEAN_TO_JSVAL(%s)" % result), True)
-
- else:
- raise TypeError("Need to learn to wrap primitive: %s" % type)
-
-def wrapForType(type, descriptorProvider, templateValues):
- """
- Reflect a C++ value of IDL type "type" into JS. TemplateValues is a dict
- that should contain:
-
- * 'jsvalRef': a C++ reference to the jsval in which to store the result of
- the conversion
- * 'jsvalPtr': a C++ pointer to the jsval in which to store the result of
- the conversion
- * 'obj' (optional): the name of the variable that contains the JSObject to
- use as a scope when wrapping, if not supplied 'obj'
- will be used as the name
- * 'result' (optional): the name of the variable in which the C++ value is
- stored, if not supplied 'result' will be used as
- the name
- * 'successCode' (optional): the code to run once we have successfully done
- the conversion, if not supplied 'return true;'
- will be used as the code
- * 'isCreator' (optional): If true, we're wrapping for the return value of
- a [Creator] method. Assumed false if not set.
- """
- wrap = getWrapTemplateForType(type, descriptorProvider,
- templateValues.get('result', 'result'),
- templateValues.get('successCode', None),
- templateValues.get('isCreator', False))[0]
-
- defaultValues = {'obj': 'obj'}
- return string.Template(wrap).substitute(defaultValues, **templateValues)
-
-def infallibleForMember(member, type, descriptorProvider):
- """
- Determine the fallibility of changing a C++ value of IDL type "type" into
- JS for the given attribute. Apart from isCreator, all the defaults are used,
- since the fallbility does not change based on the boolean values,
- and the template will be discarded.
-
- CURRENT ASSUMPTIONS:
- We assume that successCode for wrapping up return values cannot contain
- failure conditions.
- """
- return getWrapTemplateForType(type, descriptorProvider, 'result', None,\
- memberIsCreator(member))[1]
-
-def typeNeedsCx(type, retVal=False):
- if type is None:
- return False
- if type.nullable():
- type = type.inner
- if type.isSequence() or type.isArray():
- type = type.inner
- if type.isUnion():
- return any(typeNeedsCx(t) for t in type.unroll().flatMemberTypes)
- if retVal and type.isSpiderMonkeyInterface():
- return True
- return type.isCallback() or type.isAny() or type.isObject()
-
-# Returns a tuple consisting of a CGThing containing the type of the return
-# value, or None if there is no need for a return value, and a boolean signaling
-# whether the return value is passed in an out parameter.
-def getRetvalDeclarationForType(returnType, descriptorProvider,
- resultAlreadyAddRefed):
- if returnType is None or returnType.isVoid():
- # Nothing to declare
- return None, False
- if returnType.isPrimitive() and returnType.tag() in builtinNames:
- result = CGGeneric(builtinNames[returnType.tag()])
- if returnType.nullable():
- result = CGWrapper(result, pre="Nullable<", post=">")
- return result, False
- if returnType.isString():
- return CGGeneric("nsString"), True
- if returnType.isEnum():
- if returnType.nullable():
- raise TypeError("We don't support nullable enum return values")
- return CGGeneric(returnType.inner.identifier.name), False
- if returnType.isGeckoInterface():
- result = CGGeneric(descriptorProvider.getDescriptor(
- returnType.unroll().inner.identifier.name).nativeType)
- if resultAlreadyAddRefed:
- result = CGWrapper(result, pre="nsRefPtr<", post=">")
- else:
- result = CGWrapper(result, post="*")
- return result, False
- if returnType.isCallback():
- # XXXbz we're going to assume that callback types are always
- # nullable for now.
- return CGGeneric("JSObject*"), False
- if returnType.isAny():
- return CGGeneric("JS::Value"), False
- if returnType.isObject() or returnType.isSpiderMonkeyInterface():
- return CGGeneric("JSObject*"), False
- if returnType.isSequence():
- nullable = returnType.nullable()
- if nullable:
- returnType = returnType.inner
- # If our result is already addrefed, use the right type in the
- # sequence argument here.
- (result, _) = getRetvalDeclarationForType(returnType.inner,
- descriptorProvider,
- resultAlreadyAddRefed)
- result = CGWrapper(result, pre="nsTArray< ", post=" >")
- if nullable:
- result = CGWrapper(result, pre="Nullable< ", post=" >")
- return result, True
- raise TypeError("Don't know how to declare return value for %s" %
- returnType)
-
-def isResultAlreadyAddRefed(descriptor, extendedAttributes):
- # Default to already_AddRefed on the main thread, raw pointer in workers
- return not descriptor.workers and not 'resultNotAddRefed' in extendedAttributes
-
-class CGCallGenerator(CGThing):
- """
- A class to generate an actual call to a C++ object. Assumes that the C++
- object is stored in a variable whose name is given by the |object| argument.
-
- errorReport should be a CGThing for an error report or None if no
- error reporting is needed.
- """
- def __init__(self, errorReport, arguments, argsPre, returnType,
- extendedAttributes, descriptorProvider, nativeMethodName,
- static, object="self", declareResult=True):
- CGThing.__init__(self)
-
- assert errorReport is None or isinstance(errorReport, CGThing)
-
- isFallible = errorReport is not None
-
- resultAlreadyAddRefed = isResultAlreadyAddRefed(descriptorProvider,
- extendedAttributes)
- (result, resultOutParam) = getRetvalDeclarationForType(returnType,
- descriptorProvider,
- resultAlreadyAddRefed)
-
- args = CGList([CGGeneric(arg) for arg in argsPre], ", ")
- for (a, name) in arguments:
- # This is a workaround for a bug in Apple's clang.
- if a.type.isObject() and not a.type.nullable() and not a.optional:
- name = "(JSObject&)" + name
- args.append(CGGeneric(name))
-
- # Return values that go in outparams go here
- if resultOutParam:
- args.append(CGGeneric("result"))
- if isFallible:
- args.append(CGGeneric("rv"))
-
- needsCx = (typeNeedsCx(returnType, True) or
- any(typeNeedsCx(a.type) for (a, _) in arguments) or
- 'implicitJSContext' in extendedAttributes)
-
- if not "cx" in argsPre and needsCx:
- args.prepend(CGGeneric("cx"))
-
- # Build up our actual call
- self.cgRoot = CGList([], "\n")
-
- call = CGGeneric(nativeMethodName)
- if static:
- call = CGWrapper(call, pre="%s::" % descriptorProvider.nativeType)
- else:
- call = CGWrapper(call, pre="%s->" % object)
- call = CGList([call, CGWrapper(args, pre="(", post=");")])
- if result is not None:
- if declareResult:
- result = CGWrapper(result, post=" result;")
- self.cgRoot.prepend(result)
- if not resultOutParam:
- call = CGWrapper(call, pre="result = ")
-
- call = CGWrapper(call)
- self.cgRoot.append(call)
-
- if isFallible:
- self.cgRoot.prepend(CGGeneric("ErrorResult rv;"))
- self.cgRoot.append(CGGeneric("if (rv.Failed()) {"))
- self.cgRoot.append(CGIndenter(errorReport))
- self.cgRoot.append(CGGeneric("}"))
-
- def define(self):
- return self.cgRoot.define()
-
-class MethodNotCreatorError(Exception):
- def __init__(self, typename):
- self.typename = typename
-
-class CGPerSignatureCall(CGThing):
- """
- This class handles the guts of generating code for a particular
- call signature. A call signature consists of four things:
-
- 1) A return type, which can be None to indicate that there is no
- actual return value (e.g. this is an attribute setter) or an
- IDLType if there's an IDL type involved (including |void|).
- 2) An argument list, which is allowed to be empty.
- 3) A name of a native method to call.
- 4) Whether or not this method is static.
-
- We also need to know whether this is a method or a getter/setter
- to do error reporting correctly.
-
- The idlNode parameter can be either a method or an attr. We can query
- |idlNode.identifier| in both cases, so we can be agnostic between the two.
- """
- # XXXbz For now each entry in the argument list is either an
- # IDLArgument or a FakeArgument, but longer-term we may want to
- # have ways of flagging things like JSContext* or optional_argc in
- # there.
-
- def __init__(self, returnType, argsPre, arguments, nativeMethodName, static,
- descriptor, idlNode, argConversionStartsAt=0,
- getter=False, setter=False):
- CGThing.__init__(self)
- self.returnType = returnType
- self.descriptor = descriptor
- self.idlNode = idlNode
- self.extendedAttributes = descriptor.getExtendedAttributes(idlNode,
- getter=getter,
- setter=setter)
- self.argsPre = argsPre
- self.arguments = arguments
- self.argCount = len(arguments)
- if self.argCount > argConversionStartsAt:
- # Insert our argv in there
- cgThings = [CGGeneric(self.getArgvDecl())]
- else:
- cgThings = []
- cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(),
- self.getArgc(), self.descriptor,
- invalidEnumValueFatal=not setter) for
- i in range(argConversionStartsAt, self.argCount)])
-
- cgThings.append(CGCallGenerator(
- self.getErrorReport() if self.isFallible() else None,
- self.getArguments(), self.argsPre, returnType,
- self.extendedAttributes, descriptor, nativeMethodName,
- static))
- self.cgRoot = CGList(cgThings, "\n")
-
- def getArgv(self):
- return "argv" if self.argCount > 0 else ""
- def getArgvDecl(self):
- return "\nJS::Value* argv = JS_ARGV(cx, vp);\n"
- def getArgc(self):
- return "argc"
- def getArguments(self):
- return [(a, "arg" + str(i)) for (i, a) in enumerate(self.arguments)]
-
- def isFallible(self):
- return not 'infallible' in self.extendedAttributes
-
- def wrap_return_value(self):
- isCreator = memberIsCreator(self.idlNode)
- if isCreator:
- # We better be returning addrefed things!
- assert(isResultAlreadyAddRefed(self.descriptor,
- self.extendedAttributes) or
- # Workers use raw pointers for new-object return
- # values or something
- self.descriptor.workers)
-
- resultTemplateValues = { 'jsvalRef': '*vp', 'jsvalPtr': 'vp',
- 'isCreator': isCreator}
- try:
- return wrapForType(self.returnType, self.descriptor,
- resultTemplateValues)
- except MethodNotCreatorError, err:
- assert not isCreator
- raise TypeError("%s being returned from non-creator method or property %s.%s" %
- (err.typename,
- self.descriptor.interface.identifier.name,
- self.idlNode.identifier.name))
-
- def getErrorReport(self):
- return CGGeneric('return ThrowMethodFailedWithDetails<%s>(cx, rv, "%s", "%s");'
- % (toStringBool(not self.descriptor.workers),
- self.descriptor.interface.identifier.name,
- self.idlNode.identifier.name))
-
- def define(self):
- return (self.cgRoot.define() + "\n" + self.wrap_return_value())
-
-class CGSwitch(CGList):
- """
- A class to generate code for a switch statement.
-
- Takes three constructor arguments: an expression, a list of cases,
- and an optional default.
-
- Each case is a CGCase. The default is a CGThing for the body of
- the default case, if any.
- """
- def __init__(self, expression, cases, default=None):
- CGList.__init__(self, [CGIndenter(c) for c in cases], "\n")
- self.prepend(CGWrapper(CGGeneric(expression),
- pre="switch (", post=") {"));
- if default is not None:
- self.append(
- CGIndenter(
- CGWrapper(
- CGIndenter(default),
- pre="default: {\n",
- post="\n break;\n}"
- )
- )
- )
-
- self.append(CGGeneric("}"))
-
-class CGCase(CGList):
- """
- A class to generate code for a case statement.
-
- Takes three constructor arguments: an expression, a CGThing for
- the body (allowed to be None if there is no body), and an optional
- argument (defaulting to False) for whether to fall through.
- """
- def __init__(self, expression, body, fallThrough=False):
- CGList.__init__(self, [], "\n")
- self.append(CGWrapper(CGGeneric(expression), pre="case ", post=": {"))
- bodyList = CGList([body], "\n")
- if fallThrough:
- bodyList.append(CGGeneric("/* Fall through */"))
- else:
- bodyList.append(CGGeneric("break;"))
- self.append(CGIndenter(bodyList));
- self.append(CGGeneric("}"))
-
-class CGMethodCall(CGThing):
- """
- A class to generate selection of a method signature from a set of
- signatures and generation of a call to that signature.
- """
- def __init__(self, argsPre, nativeMethodName, static, descriptor, method):
- CGThing.__init__(self)
-
- methodName = '"%s.%s"' % (descriptor.interface.identifier.name, method.identifier.name)
-
- def requiredArgCount(signature):
- arguments = signature[1]
- if len(arguments) == 0:
- return 0
- requiredArgs = len(arguments)
- while requiredArgs and arguments[requiredArgs-1].optional:
- requiredArgs -= 1
- return requiredArgs
-
- def getPerSignatureCall(signature, argConversionStartsAt=0):
- return CGPerSignatureCall(signature[0], argsPre, signature[1],
- nativeMethodName, static, descriptor,
- method, argConversionStartsAt)
-
-
- signatures = method.signatures()
- if len(signatures) == 1:
- # Special case: we can just do a per-signature method call
- # here for our one signature and not worry about switching
- # on anything.
- signature = signatures[0]
- self.cgRoot = CGList([ CGIndenter(getPerSignatureCall(signature)) ])
- requiredArgs = requiredArgCount(signature)
-
-
- if requiredArgs > 0:
- code = (
- "if (argc < %d) {\n"
- " return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, %s);\n"
- "}" % (requiredArgs, methodName))
- self.cgRoot.prepend(
- CGWrapper(CGIndenter(CGGeneric(code)), pre="\n", post="\n"))
- return
-
- # Need to find the right overload
- maxArgCount = method.maxArgCount
- allowedArgCounts = method.allowedArgCounts
-
- argCountCases = []
- for argCount in allowedArgCounts:
- possibleSignatures = method.signaturesForArgCount(argCount)
- if len(possibleSignatures) == 1:
- # easy case!
- signature = possibleSignatures[0]
-
- # (possibly) important optimization: if signature[1] has >
- # argCount arguments and signature[1][argCount] is optional and
- # there is only one signature for argCount+1, then the
- # signature for argCount+1 is just ourselves and we can fall
- # through.
- if (len(signature[1]) > argCount and
- signature[1][argCount].optional and
- (argCount+1) in allowedArgCounts and
- len(method.signaturesForArgCount(argCount+1)) == 1):
- argCountCases.append(
- CGCase(str(argCount), None, True))
- else:
- argCountCases.append(
- CGCase(str(argCount), getPerSignatureCall(signature)))
- continue
-
- distinguishingIndex = method.distinguishingIndexForArgCount(argCount)
-
- # We can't handle unions at the distinguishing index.
- for (returnType, args) in possibleSignatures:
- if args[distinguishingIndex].type.isUnion():
- raise TypeError("No support for unions as distinguishing "
- "arguments yet: %s",
- args[distinguishingIndex].location)
-
- # Convert all our arguments up to the distinguishing index.
- # Doesn't matter which of the possible signatures we use, since
- # they all have the same types up to that point; just use
- # possibleSignatures[0]
- caseBody = [CGGeneric("JS::Value* argv_start = JS_ARGV(cx, vp);")]
- caseBody.extend([ CGArgumentConverter(possibleSignatures[0][1][i],
- i, "argv_start", "argc",
- descriptor) for i in
- range(0, distinguishingIndex) ])
-
- # Select the right overload from our set.
- distinguishingArg = "argv_start[%d]" % distinguishingIndex
-
- def pickFirstSignature(condition, filterLambda):
- sigs = filter(filterLambda, possibleSignatures)
- assert len(sigs) < 2
- if len(sigs) > 0:
- if condition is None:
- caseBody.append(
- getPerSignatureCall(sigs[0], distinguishingIndex))
- else:
- caseBody.append(CGGeneric("if (" + condition + ") {"))
- caseBody.append(CGIndenter(
- getPerSignatureCall(sigs[0], distinguishingIndex)))
- caseBody.append(CGGeneric("}"))
- return True
- return False
-
- # First check for null or undefined
- pickFirstSignature("%s.isNullOrUndefined()" % distinguishingArg,
- lambda s: (s[1][distinguishingIndex].type.nullable() or
- s[1][distinguishingIndex].type.isDictionary()))
-
- # Now check for distinguishingArg being an object that implements a
- # non-callback interface. That includes typed arrays and
- # arraybuffers.
- interfacesSigs = [
- s for s in possibleSignatures
- if (s[1][distinguishingIndex].type.isObject() or
- s[1][distinguishingIndex].type.isNonCallbackInterface()) ]
- # There might be more than one of these; we need to check
- # which ones we unwrap to.
-
- if len(interfacesSigs) > 0:
- # The spec says that we should check for "platform objects
- # implementing an interface", but it's enough to guard on these
- # being an object. The code for unwrapping non-callback
- # interfaces and typed arrays will just bail out and move on to
- # the next overload if the object fails to unwrap correctly. We
- # could even not do the isObject() check up front here, but in
- # cases where we have multiple object overloads it makes sense
- # to do it only once instead of for each overload. That will
- # also allow the unwrapping test to skip having to do codegen
- # for the null-or-undefined case, which we already handled
- # above.
- caseBody.append(CGGeneric("if (%s.isObject()) {" %
- (distinguishingArg)))
- for sig in interfacesSigs:
- caseBody.append(CGIndenter(CGGeneric("do {")));
- type = sig[1][distinguishingIndex].type
-
- # The argument at index distinguishingIndex can't possibly
- # be unset here, because we've already checked that argc is
- # large enough that we can examine this argument.
- testCode = instantiateJSToNativeConversionTemplate(
- getJSToNativeConversionTemplate(type, descriptor,
- failureCode="break;",
- isDefinitelyObject=True),
- {
- "declName" : "arg%d" % distinguishingIndex,
- "holderName" : ("arg%d" % distinguishingIndex) + "_holder",
- "val" : distinguishingArg
- })
-
- # Indent by 4, since we need to indent further than our "do" statement
- caseBody.append(CGIndenter(testCode, 4));
- # If we got this far, we know we unwrapped to the right
- # interface, so just do the call. Start conversion with
- # distinguishingIndex + 1, since we already converted
- # distinguishingIndex.
- caseBody.append(CGIndenter(
- getPerSignatureCall(sig, distinguishingIndex + 1), 4))
- caseBody.append(CGIndenter(CGGeneric("} while (0);")))
-
- caseBody.append(CGGeneric("}"))
-
- # XXXbz Now we're supposed to check for distinguishingArg being
- # an array or a platform object that supports indexed
- # properties... skip that last for now. It's a bit of a pain.
- pickFirstSignature("%s.isObject() && IsArrayLike(cx, &%s.toObject())" %
- (distinguishingArg, distinguishingArg),
- lambda s:
- (s[1][distinguishingIndex].type.isArray() or
- s[1][distinguishingIndex].type.isSequence() or
- s[1][distinguishingIndex].type.isObject()))
-
- # Check for Date objects
- # XXXbz Do we need to worry about security wrappers around the Date?
- pickFirstSignature("%s.isObject() && JS_ObjectIsDate(cx, &%s.toObject())" %
- (distinguishingArg, distinguishingArg),
- lambda s: (s[1][distinguishingIndex].type.isDate() or
- s[1][distinguishingIndex].type.isObject()))
-
- # Check for vanilla JS objects
- # XXXbz Do we need to worry about security wrappers?
- pickFirstSignature("%s.isObject() && !IsPlatformObject(cx, &%s.toObject())" %
- (distinguishingArg, distinguishingArg),
- lambda s: (s[1][distinguishingIndex].type.isCallback() or
- s[1][distinguishingIndex].type.isCallbackInterface() or
- s[1][distinguishingIndex].type.isDictionary() or
- s[1][distinguishingIndex].type.isObject()))
-
- # The remaining cases are mutually exclusive. The
- # pickFirstSignature calls are what change caseBody
- # Check for strings or enums
- if pickFirstSignature(None,
- lambda s: (s[1][distinguishingIndex].type.isString() or
- s[1][distinguishingIndex].type.isEnum())):
- pass
- # Check for primitives
- elif pickFirstSignature(None,
- lambda s: s[1][distinguishingIndex].type.isPrimitive()):
- pass
- # Check for "any"
- elif pickFirstSignature(None,
- lambda s: s[1][distinguishingIndex].type.isAny()):
- pass
- else:
- # Just throw; we have no idea what we're supposed to
- # do with this.
- caseBody.append(CGGeneric("return Throw<%s>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);" %
- toStringBool(not descriptor.workers)))
-
- argCountCases.append(CGCase(str(argCount),
- CGList(caseBody, "\n")))
-
- overloadCGThings = []
- overloadCGThings.append(
- CGGeneric("unsigned argcount = NS_MIN(argc, %du);" %
- maxArgCount))
- overloadCGThings.append(
- CGSwitch("argcount",
- argCountCases,
- CGGeneric("return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, %s);\n" % methodName)))
- overloadCGThings.append(
- CGGeneric('MOZ_NOT_REACHED("We have an always-returning default case");\n'
- 'return false;'))
- self.cgRoot = CGWrapper(CGIndenter(CGList(overloadCGThings, "\n")),
- pre="\n")
-
- def define(self):
- return self.cgRoot.define()
-
-class CGGetterCall(CGPerSignatureCall):
- """
- A class to generate a native object getter call for a particular IDL
- getter.
- """
- def __init__(self, returnType, nativeMethodName, descriptor, attr):
- CGPerSignatureCall.__init__(self, returnType, [], [],
- nativeMethodName, False, descriptor,
- attr, getter=True)
-
-class FakeArgument():
- """
- A class that quacks like an IDLArgument. This is used to make
- setters look like method calls or for special operations.
- """
- def __init__(self, type, interfaceMember):
- self.type = type
- self.optional = False
- self.variadic = False
- self.defaultValue = None
- self.treatNullAs = interfaceMember.treatNullAs
- self.treatUndefinedAs = interfaceMember.treatUndefinedAs
- self.enforceRange = False
- self.clamp = False
-
-class CGSetterCall(CGPerSignatureCall):
- """
- A class to generate a native object setter call for a particular IDL
- setter.
- """
- def __init__(self, argType, nativeMethodName, descriptor, attr):
- CGPerSignatureCall.__init__(self, None, [],
- [FakeArgument(argType, attr)],
- nativeMethodName, False, descriptor, attr,
- setter=True)
- def wrap_return_value(self):
- # We have no return value
- return "\nreturn true;"
- def getArgc(self):
- return "1"
- def getArgvDecl(self):
- # We just get our stuff from our last arg no matter what
- return ""
-
-class FakeCastableDescriptor():
- def __init__(self, descriptor):
- self.castable = True
- self.workers = descriptor.workers
- self.nativeType = descriptor.nativeType
- self.name = descriptor.name
- self.hasXPConnectImpls = descriptor.hasXPConnectImpls
-
-class CGAbstractBindingMethod(CGAbstractStaticMethod):
- """
- Common class to generate the JSNatives for all our methods, getters, and
- setters. This will generate the function declaration and unwrap the
- |this| object. Subclasses are expected to override the generate_code
- function to do the rest of the work. This function should return a
- CGThing which is already properly indented.
- """
- def __init__(self, descriptor, name, args, unwrapFailureCode=None):
- CGAbstractStaticMethod.__init__(self, descriptor, name, "JSBool", args)
-
- if unwrapFailureCode is None:
- self.unwrapFailureCode = ("return Throw<%s>(cx, rv);" %
- toStringBool(not descriptor.workers))
- else:
- self.unwrapFailureCode = unwrapFailureCode
-
- def definition_body(self):
- # Our descriptor might claim that we're not castable, simply because
- # we're someone's consequential interface. But for this-unwrapping, we
- # know that we're the real deal. So fake a descriptor here for
- # consumption by FailureFatalCastableObjectUnwrapper.
- unwrapThis = CGIndenter(CGGeneric(
- str(CastableObjectUnwrapper(
- FakeCastableDescriptor(self.descriptor),
- "obj", "self", self.unwrapFailureCode))))
- return CGList([ self.getThis(), unwrapThis,
- self.generate_code() ], "\n").define()
-
- def getThis(self):
- return CGIndenter(
- CGGeneric("js::RootedObject obj(cx, JS_THIS_OBJECT(cx, vp));\n"
- "if (!obj) {\n"
- " return false;\n"
- "}\n"
- "\n"
- "%s* self;" % self.descriptor.nativeType))
-
- def generate_code(self):
- assert(False) # Override me
-
-def MakeNativeName(name):
- return name[0].upper() + name[1:]
-
-class CGGenericMethod(CGAbstractBindingMethod):
- """
- A class for generating the C++ code for an IDL method..
- """
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
- Argument('JS::Value*', 'vp')]
- CGAbstractBindingMethod.__init__(self, descriptor, 'genericMethod', args)
-
- def generate_code(self):
- return CGIndenter(CGGeneric(
- "const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "JSJitMethodOp method = (JSJitMethodOp)info->op;\n"
- "return method(cx, obj, self, argc, vp);"))
-
-class CGSpecializedMethod(CGAbstractStaticMethod):
- """
- A class for generating the C++ code for a specialized method that the JIT
- can call with lower overhead.
- """
- def __init__(self, descriptor, method):
- self.method = method
- name = method.identifier.name
- args = [Argument('JSContext*', 'cx'), Argument('JSHandleObject', 'obj'),
- Argument('%s*' % descriptor.nativeType, 'self'),
- Argument('unsigned', 'argc'), Argument('JS::Value*', 'vp')]
- CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args)
-
- def definition_body(self):
- name = self.method.identifier.name
- nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
- return CGMethodCall([], nativeName, self.method.isStatic(),
- self.descriptor, self.method).define()
-
-class CGGenericGetter(CGAbstractBindingMethod):
- """
- A class for generating the C++ code for an IDL attribute getter.
- """
- def __init__(self, descriptor, lenientThis=False):
- args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
- Argument('JS::Value*', 'vp')]
- if lenientThis:
- name = "genericLenientGetter"
- unwrapFailureCode = (
- "MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"
- "JS_SET_RVAL(cx, vp, JS::UndefinedValue());\n"
- "return true;")
- else:
- name = "genericGetter"
- unwrapFailureCode = None
- CGAbstractBindingMethod.__init__(self, descriptor, name, args,
- unwrapFailureCode)
-
- def generate_code(self):
- return CGIndenter(CGGeneric(
- "const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "JSJitPropertyOp getter = info->op;\n"
- "return getter(cx, obj, self, vp);"))
-
-class CGSpecializedGetter(CGAbstractStaticMethod):
- """
- A class for generating the code for a specialized attribute getter
- that the JIT can call with lower overhead.
- """
- def __init__(self, descriptor, attr):
- self.attr = attr
- name = 'get_' + attr.identifier.name
- args = [ Argument('JSContext*', 'cx'),
- Argument('JSHandleObject', 'obj'),
- Argument('%s*' % descriptor.nativeType, 'self'),
- Argument('JS::Value*', 'vp') ]
- CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
-
- def definition_body(self):
- name = self.attr.identifier.name
- nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
- # resultOutParam does not depend on whether resultAlreadyAddRefed is set
- (_, resultOutParam) = getRetvalDeclarationForType(self.attr.type,
- self.descriptor,
- False)
- infallible = ('infallible' in
- self.descriptor.getExtendedAttributes(self.attr,
- getter=True))
- if resultOutParam or self.attr.type.nullable() or not infallible:
- nativeName = "Get" + nativeName
- return CGIndenter(CGGetterCall(self.attr.type, nativeName,
- self.descriptor, self.attr)).define()
-
-class CGGenericSetter(CGAbstractBindingMethod):
- """
- A class for generating the C++ code for an IDL attribute setter.
- """
- def __init__(self, descriptor, lenientThis=False):
- args = [Argument('JSContext*', 'cx'), Argument('unsigned', 'argc'),
- Argument('JS::Value*', 'vp')]
- if lenientThis:
- name = "genericLenientSetter"
- unwrapFailureCode = (
- "MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"
- "return true;")
- else:
- name = "genericSetter"
- unwrapFailureCode = None
- CGAbstractBindingMethod.__init__(self, descriptor, name, args,
- unwrapFailureCode)
-
- def generate_code(self):
- return CGIndenter(CGGeneric(
- "JS::Value* argv = JS_ARGV(cx, vp);\n"
- "JS::Value undef = JS::UndefinedValue();\n"
- "if (argc == 0) {\n"
- " argv = &undef;\n"
- "}\n"
- "const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n"
- "JSJitPropertyOp setter = info->op;\n"
- "if (!setter(cx, obj, self, argv)) {\n"
- " return false;\n"
- "}\n"
- "*vp = JSVAL_VOID;\n"
- "return true;"))
-
-class CGSpecializedSetter(CGAbstractStaticMethod):
- """
- A class for generating the code for a specialized attribute setter
- that the JIT can call with lower overhead.
- """
- def __init__(self, descriptor, attr):
- self.attr = attr
- name = 'set_' + attr.identifier.name
- args = [ Argument('JSContext*', 'cx'),
- Argument('JSHandleObject', 'obj'),
- Argument('%s*' % descriptor.nativeType, 'self'),
- Argument('JS::Value*', 'argv')]
- CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args)
-
- def definition_body(self):
- name = self.attr.identifier.name
- nativeName = "Set" + MakeNativeName(self.descriptor.binaryNames.get(name, name))
- return CGIndenter(CGSetterCall(self.attr.type, nativeName,
- self.descriptor, self.attr)).define()
-
-def memberIsCreator(member):
- return member.getExtendedAttribute("Creator") is not None
-
-class CGMemberJITInfo(CGThing):
- """
- A class for generating the JITInfo for a property that points to
- our specialized getter and setter.
- """
- def __init__(self, descriptor, member):
- self.member = member
- self.descriptor = descriptor
-
- def declare(self):
- return ""
-
- def defineJitInfo(self, infoName, opName, infallible):
- protoID = "prototypes::id::%s" % self.descriptor.name
- depth = "PrototypeTraits<%s>::Depth" % protoID
- failstr = "true" if infallible else "false"
- return ("\n"
- "const JSJitInfo %s = {\n"
- " %s,\n"
- " %s,\n"
- " %s,\n"
- " %s, /* isInfallible. False in setters. */\n"
- " false /* isConstant. Only relevant for getters. */\n"
- "};\n" % (infoName, opName, protoID, depth, failstr))
-
- def define(self):
- if self.member.isAttr():
- getterinfo = ("%s_getterinfo" % self.member.identifier.name)
- getter = ("(JSJitPropertyOp)get_%s" % self.member.identifier.name)
- getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True)
- getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor)
- result = self.defineJitInfo(getterinfo, getter, getterinfal)
- if not self.member.readonly:
- setterinfo = ("%s_setterinfo" % self.member.identifier.name)
- setter = ("(JSJitPropertyOp)set_%s" % self.member.identifier.name)
- # Setters are always fallible, since they have to do a typed unwrap.
- result += self.defineJitInfo(setterinfo, setter, False)
- return result
- if self.member.isMethod():
- methodinfo = ("%s_methodinfo" % self.member.identifier.name)
- # Actually a JSJitMethodOp, but JSJitPropertyOp by struct definition.
- method = ("(JSJitPropertyOp)%s" % self.member.identifier.name)
-
- # Methods are infallible if they are infallible, have no arguments
- # to unwrap, and have a return type that's infallible to wrap up for
- # return.
- methodInfal = False
- sigs = self.member.signatures()
- if len(sigs) == 1:
- # Don't handle overloading. If there's more than one signature,
- # one of them must take arguments.
- sig = sigs[0]
- if len(sig[1]) == 0 and infallibleForMember(self.member, sig[0], self.descriptor):
- # No arguments and infallible return boxing
- methodInfal = True
-
- result = self.defineJitInfo(methodinfo, method, methodInfal)
- return result
- raise TypeError("Illegal member type to CGPropertyJITInfo")
-
-def getEnumValueName(value):
- # Some enum values can be empty strings. Others might have weird
- # characters in them. Deal with the former by returning "_empty",
- # deal with possible name collisions from that by throwing if the
- # enum value is actually "_empty", and throw on any value
- # containing chars other than [a-z] or '-' for now. Replace '-' with '_'.
- value = value.replace('-', '_')
- if value == "_empty":
- raise SyntaxError('"_empty" is not an IDL enum value we support yet')
- if value == "":
- return "_empty"
- if not re.match("^[a-z_]+$", value):
- raise SyntaxError('Enum value "' + value + '" contains characters '
- 'outside [a-z_]')
- return MakeNativeName(value)
-
-class CGEnum(CGThing):
- def __init__(self, enum):
- CGThing.__init__(self)
- self.enum = enum
-
- def declare(self):
- return """
- enum valuelist {
- %s
- };
-
- extern const EnumEntry strings[%d];
-""" % (",\n ".join(map(getEnumValueName, self.enum.values())),
- len(self.enum.values()) + 1)
-
- def define(self):
- return """
- const EnumEntry strings[%d] = {
- %s,
- { NULL, 0 }
- };
-""" % (len(self.enum.values()) + 1,
- ",\n ".join(['{"' + val + '", ' + str(len(val)) + '}' for val in self.enum.values()]))
-
-def getUnionAccessorSignatureType(type, descriptorProvider):
- """
- Returns the types that are used in the getter and setter signatures for
- union types
- """
- if type.isArray():
- raise TypeError("Can't handle array arguments yet")
-
- if type.isSequence():
- nullable = type.nullable();
- if nullable:
- type = type.inner.inner
- else:
- type = type.inner
- (elementTemplate, elementDeclType,
- elementHolderType, dealWithOptional) = getJSToNativeConversionTemplate(
- type, descriptorProvider, isSequenceMember=True)
- typeName = CGWrapper(elementDeclType, pre="Sequence< ", post=" >&")
- if nullable:
- typeName = CGWrapper(typeName, pre="Nullable< ", post=" >&")
-
- return typeName
-
- if type.isUnion():
- typeName = CGGeneric(type.name)
- if type.nullable():
- typeName = CGWrapper(typeName, pre="Nullable< ", post=" >&")
-
- return typeName
-
- if type.isGeckoInterface():
- descriptor = descriptorProvider.getDescriptor(
- type.unroll().inner.identifier.name)
- typeName = CGGeneric(descriptor.nativeType)
- # Allow null pointers for nullable types and old-binding classes
- if type.nullable() or type.unroll().inner.isExternal():
- typeName = CGWrapper(typeName, post="*")
- else:
- typeName = CGWrapper(typeName, post="&")
- return typeName
-
- if type.isSpiderMonkeyInterface():
- typeName = CGGeneric(type.name)
- if type.nullable():
- typeName = CGWrapper(typeName, post="*")
- else:
- typeName = CGWrapper(typeName, post="&")
- return typeName
-
- if type.isString():
- return CGGeneric("const nsAString&")
-
- if type.isEnum():
- if type.nullable():
- raise TypeError("We don't support nullable enumerated arguments or "
- "union members yet")
- return CGGeneric(type.inner.identifier.name)
-
- if type.isCallback():
- return CGGeneric("JSObject*")
-
- if type.isAny():
- return CGGeneric("JS::Value")
-
- if type.isObject():
- typeName = CGGeneric("JSObject")
- if type.nullable():
- typeName = CGWrapper(typeName, post="*")
- else:
- typeName = CGWrapper(typeName, post="&")
- return typeName
-
- if not type.isPrimitive():
- raise TypeError("Need native type for argument type '%s'" % str(type))
-
- typeName = CGGeneric(builtinNames[type.tag()])
- if type.nullable():
- typeName = CGWrapper(typeName, pre="Nullable< ", post=" >&")
- return typeName
-
-def getUnionTypeTemplateVars(type, descriptorProvider):
- # For dictionaries and sequences we need to pass None as the failureCode
- # for getJSToNativeConversionTemplate.
- # Also, for dictionaries we would need to handle conversion of
- # null/undefined to the dictionary correctly.
- if type.isDictionary() or type.isSequence():
- raise TypeError("Can't handle dictionaries or sequences in unions")
-
- if type.isGeckoInterface():
- name = type.inner.identifier.name
- elif type.isEnum():
- name = type.inner.identifier.name
- elif type.isArray() or type.isSequence():
- name = str(type)
- else:
- name = type.name
-
- tryNextCode = """tryNext = true;
-return true;"""
- if type.isGeckoInterface():
- tryNextCode = ("""if (mUnion.mType != mUnion.eUninitialized) {
- mUnion.Destroy%s();
-}""" % name) + tryNextCode
- (template, declType, holderType,
- dealWithOptional) = getJSToNativeConversionTemplate(
- type, descriptorProvider, failureCode=tryNextCode,
- isDefinitelyObject=True)
-
- # This is ugly, but UnionMember needs to call a constructor with no
- # arguments so the type can't be const.
- structType = declType.define()
- if structType.startswith("const "):
- structType = structType[6:]
- externalType = getUnionAccessorSignatureType(type, descriptorProvider).define()
-
- if type.isObject():
- setter = CGGeneric("void SetToObject(JSObject* obj)\n"
- "{\n"
- " mUnion.mValue.mObject.SetValue() = obj;\n"
- " mUnion.mType = mUnion.eObject;\n"
- "}")
- else:
- jsConversion = string.Template(template).substitute(
- {
- "val": "value",
- "valPtr": "pvalue",
- "declName": "SetAs" + name + "()",
- "holderName": "m" + name + "Holder"
- }
- )
- jsConversion = CGWrapper(CGGeneric(jsConversion),
- post="\n"
- "return true;")
- setter = CGWrapper(CGIndenter(jsConversion),
- pre="bool TrySetTo" + name + "(JSContext* cx, const JS::Value& value, JS::Value* pvalue, bool& tryNext)\n"
- "{\n"
- " tryNext = false;\n",
- post="\n"
- "}")
-
- return {
- "name": name,
- "structType": structType,
- "externalType": externalType,
- "setter": CGIndenter(setter).define(),
- "holderType": holderType.define() if holderType else None
- }
-
-def mapTemplate(template, templateVarArray):
- return map(lambda v: string.Template(template).substitute(v),
- templateVarArray)
-
-class CGUnionStruct(CGThing):
- def __init__(self, type, descriptorProvider):
- CGThing.__init__(self)
- self.type = type.unroll()
- self.descriptorProvider = descriptorProvider
-
- def declare(self):
- templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider),
- self.type.flatMemberTypes)
-
- callDestructors = []
- enumValues = []
- methods = []
- if self.type.hasNullableType:
- callDestructors.append(" case eNull:\n"
- " break;")
- enumValues.append("eNull")
- methods.append(""" bool IsNull() const
- {
- return mType == eNull;
- }""")
-
- destructorTemplate = """ void Destroy${name}()
- {
- MOZ_ASSERT(Is${name}(), "Wrong type!");
- mValue.m${name}.Destroy();
- mType = eUninitialized;
- }"""
- destructors = mapTemplate(destructorTemplate, templateVars)
- callDestructors.extend(mapTemplate(" case e${name}:\n"
- " Destroy${name}();\n"
- " break;", templateVars))
- enumValues.extend(mapTemplate("e${name}", templateVars))
- methodTemplate = """ bool Is${name}() const
- {
- return mType == e${name};
- }
- ${externalType} GetAs${name}() const
- {
- MOZ_ASSERT(Is${name}(), "Wrong type!");
- // The cast to ${externalType} is needed to work around a bug in Apple's
- // clang compiler, for some reason it doesn't call |S::operator T&| when
- // casting S<T> to T& and T is forward declared.
- return (${externalType})mValue.m${name}.Value();
- }
- ${structType}& SetAs${name}()
- {
- mType = e${name};
- return mValue.m${name}.SetValue();
- }"""
- methods.extend(mapTemplate(methodTemplate, templateVars))
- values = mapTemplate("UnionMember<${structType} > m${name};", templateVars)
- return string.Template("""
-class ${structName} {
-public:
- ${structName}() : mType(eUninitialized)
- {
- }
- ~${structName}()
- {
- switch (mType) {
-${callDestructors}
- case eUninitialized:
- break;
- }
- }
-
-${methods}
-
-private:
- friend class ${structName}Argument;
-
-${destructors}
-
- enum Type {
- eUninitialized,
- ${enumValues}
- };
- union Value {
- ${values}
- };
-
- Type mType;
- Value mValue;
-};
-
-""").substitute(
- {
- "structName": self.type.__str__(),
- "callDestructors": "\n".join(callDestructors),
- "destructors": "\n".join(destructors),
- "methods": "\n\n".join(methods),
- "enumValues": ",\n ".join(enumValues),
- "values": "\n ".join(values),
- })
-
- def define(self):
- return """
-"""
-
-class CGUnionConversionStruct(CGThing):
- def __init__(self, type, descriptorProvider):
- CGThing.__init__(self)
- self.type = type.unroll()
- self.descriptorProvider = descriptorProvider
-
- def declare(self):
- setters = []
-
- if self.type.hasNullableType:
- setters.append(""" bool SetNull()
- {
- mUnion.mType = mUnion.eNull;
- return true;
- }""")
-
- templateVars = map(lambda t: getUnionTypeTemplateVars(t, self.descriptorProvider),
- self.type.flatMemberTypes)
- structName = self.type.__str__()
-
- setters.extend(mapTemplate("${setter}", templateVars))
- private = "\n".join(mapTemplate(""" ${structType}& SetAs${name}()
- {
- mUnion.mType = mUnion.e${name};
- return mUnion.mValue.m${name}.SetValue();
- }""", templateVars))
- private += "\n\n"
- holders = filter(lambda v: v["holderType"] is not None, templateVars)
- if len(holders) > 0:
- private += "\n".join(mapTemplate(" ${holderType} m${name}Holder;", holders))
- private += "\n\n"
- private += " " + structName + "& mUnion;"
- return string.Template("""
-class ${structName}Argument {
-public:
- ${structName}Argument(const ${structName}& aUnion) : mUnion(const_cast<${structName}&>(aUnion))
- {
- }
-
-${setters}
-
-private:
-${private}
-};
-""").substitute({"structName": structName,
- "setters": "\n\n".join(setters),
- "private": private
- })
-
- def define(self):
- return """
-"""
-
-class ClassItem:
- """ Use with CGClass """
- def __init__(self, name, visibility):
- self.name = name
- self.visibility = visibility
- def declare(self, cgClass):
- assert False
- def define(self, cgClass):
- assert False
-
-class ClassBase(ClassItem):
- def __init__(self, name, visibility='public'):
- ClassItem.__init__(self, name, visibility)
- def declare(self, cgClass):
- return '%s %s' % (self.visibility, self.name)
- def define(self, cgClass):
- # Only in the header
- return ''
-
-class ClassMethod(ClassItem):
- def __init__(self, name, returnType, args, inline=False, static=False,
- virtual=False, const=False, bodyInHeader=False,
- templateArgs=None, visibility='public', body=None):
- self.returnType = returnType
- self.args = args
- self.inline = inline or bodyInHeader
- self.static = static
- self.virtual = virtual
- self.const = const
- self.bodyInHeader = bodyInHeader
- self.templateArgs = templateArgs
- self.body = body
- ClassItem.__init__(self, name, visibility)
-
- def getDecorators(self, declaring):
- decorators = []
- if self.inline:
- decorators.append('inline')
- if declaring:
- if self.static:
- decorators.append('static')
- if self.virtual:
- decorators.append('virtual')
- if decorators:
- return ' '.join(decorators) + ' '
- return ''
-
- def getBody(self):
- # Override me or pass a string to constructor
- assert self.body is not None
- return self.body
-
- def declare(self, cgClass):
- templateClause = 'template <%s>\n' % ', '.join(self.templateArgs) \
- if self.bodyInHeader and self.templateArgs else ''
- args = ', '.join([str(a) for a in self.args])
- if self.bodyInHeader:
- body = CGIndenter(CGGeneric(self.getBody())).define()
- body = '\n{\n' + body + '\n}'
- else:
- body = ';'
-
- return string.Template("""${templateClause}${decorators}${returnType}
-${name}(${args})${const}${body}
-""").substitute({ 'templateClause': templateClause,
- 'decorators': self.getDecorators(True),
- 'returnType': self.returnType,
- 'name': self.name,
- 'const': ' const' if self.const else '',
- 'args': args,
- 'body': body })
-
- def define(self, cgClass):
- if self.bodyInHeader:
- return ''
-
- templateArgs = cgClass.templateArgs
- if templateArgs:
- if cgClass.templateSpecialization:
- templateArgs = \
- templateArgs[len(cgClass.templateSpecialization):]
-
- if templateArgs:
- templateClause = \
- 'template <%s>\n' % ', '.join([str(a) for a in templateArgs])
- else:
- templateClause = ''
-
- args = ', '.join([str(a) for a in self.args])
-
- body = CGIndenter(CGGeneric(self.getBody())).define()
-
- return string.Template("""${templateClause}${decorators}${returnType}
-${className}::${name}(${args})${const}
-{
-${body}
-}\n
-""").substitute({ 'templateClause': templateClause,
- 'decorators': self.getDecorators(False),
- 'returnType': self.returnType,
- 'className': cgClass.getNameString(),
- 'name': self.name,
- 'args': args,
- 'const': ' const' if self.const else '',
- 'body': body })
-
-class ClassConstructor(ClassItem):
- """
- Used for adding a constructor to a CGClass.
-
- args is a list of Argument objects that are the arguments taken by the
- constructor.
-
- inline should be True if the constructor should be marked inline.
-
- bodyInHeader should be True if the body should be placed in the class
- declaration in the header.
-
- visibility determines the visibility of the constructor (public,
- protected, private), defaults to private.
-
- baseConstructors is a list of strings containing calls to base constructors,
- defaults to None.
-
- body contains a string with the code for the constructor, defaults to None.
- """
- def __init__(self, args, inline=False, bodyInHeader=False,
- visibility="private", baseConstructors=None, body=None):
- self.args = args
- self.inline = inline or bodyInHeader
- self.bodyInHeader = bodyInHeader
- self.baseConstructors = baseConstructors
- self.body = body
- ClassItem.__init__(self, None, visibility)
-
- def getDecorators(self, declaring):
- decorators = []
- if self.inline and declaring:
- decorators.append('inline')
- if decorators:
- return ' '.join(decorators) + ' '
- return ''
-
- def getInitializationList(self, cgClass):
- items = [str(c) for c in self.baseConstructors]
- for m in cgClass.members:
- if not m.static:
- initialize = m.getBody()
- if initialize:
- items.append(m.name + "(" + initialize + ")")
-
- if len(items) > 0:
- return '\n : ' + ',\n '.join(items)
- return ''
-
- def getBody(self):
- assert self.body is not None
- return self.body
-
- def declare(self, cgClass):
- args = ', '.join([str(a) for a in self.args])
- if self.bodyInHeader:
- body = ' ' + self.getBody();
- body = stripTrailingWhitespace(body.replace('\n', '\n '))
- if len(body) > 0:
- body += '\n'
- body = self.getInitializationList(cgClass) + '\n{\n' + body + '}'
- else:
- body = ';'
-
- return string.Template("""${decorators}${className}(${args})${body}
-""").substitute({ 'decorators': self.getDecorators(True),
- 'className': cgClass.getNameString(),
- 'args': args,
- 'body': body })
-
- def define(self, cgClass):
- if self.bodyInHeader:
- return ''
-
- args = ', '.join([str(a) for a in self.args])
-
- body = ' ' + self.getBody()
- body = '\n' + stripTrailingWhitespace(body.replace('\n', '\n '))
- if len(body) > 0:
- body += '\n'
-
- return string.Template("""${decorators}
-${className}::${className}(${args})${initializationList}
-{${body}}\n
-""").substitute({ 'decorators': self.getDecorators(False),
- 'className': cgClass.getNameString(),
- 'args': args,
- 'initializationList': self.getInitializationList(cgClass),
- 'body': body })
-
-class ClassMember(ClassItem):
- def __init__(self, name, type, visibility="private", static=False,
- body=None):
- self.type = type;
- self.static = static
- self.body = body
- ClassItem.__init__(self, name, visibility)
-
- def declare(self, cgClass):
- return '%s%s %s;\n' % ('static ' if self.static else '', self.type,
- self.name)
-
- def define(self, cgClass):
- if not self.static:
- return ''
- if self.body:
- body = " = " + self.body
- else:
- body = ""
- return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(),
- self.name, body)
-
-class ClassTypedef(ClassItem):
- def __init__(self, name, type, visibility="public"):
- self.type = type
- ClassItem.__init__(self, name, visibility)
-
- def declare(self, cgClass):
- return 'typedef %s %s;\n' % (self.type, self.name)
-
- def define(self, cgClass):
- # Only goes in the header
- return ''
-
-class ClassEnum(ClassItem):
- def __init__(self, name, entries, values=None, visibility="public"):
- self.entries = entries
- self.values = values
- ClassItem.__init__(self, name, visibility)
-
- def declare(self, cgClass):
- entries = []
- for i in range(0, len(self.entries)):
- if i >= len(self.values):
- entry = '%s' % self.entries[i]
- else:
- entry = '%s = %s' % (self.entries[i], self.values[i])
- entries.append(entry)
- name = '' if not self.name else ' ' + self.name
- return 'enum%s\n{\n %s\n};\n' % (name, ',\n '.join(entries))
-
- def define(self, cgClass):
- # Only goes in the header
- return ''
-
-class CGClass(CGThing):
- def __init__(self, name, bases=[], members=[], constructors=[], methods=[],
- typedefs = [], enums=[], templateArgs=[],
- templateSpecialization=[], isStruct=False, indent=''):
- CGThing.__init__(self)
- self.name = name
- self.bases = bases
- self.members = members
- self.constructors = constructors
- self.methods = methods
- self.typedefs = typedefs
- self.enums = enums
- self.templateArgs = templateArgs
- self.templateSpecialization = templateSpecialization
- self.isStruct = isStruct
- self.indent = indent
- self.defaultVisibility ='public' if isStruct else 'private'
-
- def getNameString(self):
- className = self.name
- if self.templateSpecialization:
- className = className + \
- '<%s>' % ', '.join([str(a) for a
- in self.templateSpecialization])
- return className
-
- def declare(self):
- result = ''
- if self.templateArgs:
- templateArgs = [str(a) for a in self.templateArgs]
- templateArgs = templateArgs[len(self.templateSpecialization):]
- result = result + self.indent + 'template <%s>\n' \
- % ','.join([str(a) for a in templateArgs])
-
- type = 'struct' if self.isStruct else 'class'
-
- if self.templateSpecialization:
- specialization = \
- '<%s>' % ', '.join([str(a) for a in self.templateSpecialization])
- else:
- specialization = ''
-
- result = result + '%s%s %s%s' \
- % (self.indent, type, self.name, specialization)
-
- if self.bases:
- result = result + ' : %s' % ', '.join([d.declare(self) for d in self.bases])
-
- result = result + '\n%s{\n' % self.indent
-
- def declareMembers(cgClass, memberList, defaultVisibility, itemCount,
- separator=''):
- members = { 'private': [], 'protected': [], 'public': [] }
-
- for member in memberList:
- members[member.visibility].append(member)
-
-
- if defaultVisibility == 'public':
- order = [ 'public', 'protected', 'private' ]
- else:
- order = [ 'private', 'protected', 'public' ]
-
- result = ''
-
- lastVisibility = defaultVisibility
- for visibility in order:
- list = members[visibility]
- if list:
- if visibility != lastVisibility:
- if itemCount:
- result = result + '\n'
- result = result + visibility + ':\n'
- itemCount = 0
- for member in list:
- if itemCount != 0:
- result = result + separator
- declaration = member.declare(cgClass)
- declaration = CGIndenter(CGGeneric(declaration)).define()
- result = result + declaration
- itemCount = itemCount + 1
- lastVisibility = visibility
- return (result, lastVisibility, itemCount)
-
- order = [(self.enums, ''), (self.typedefs, ''), (self.members, ''),
- (self.constructors, '\n'), (self.methods, '\n')]
-
- lastVisibility = self.defaultVisibility
- itemCount = 0
- for (memberList, separator) in order:
- (memberString, lastVisibility, itemCount) = \
- declareMembers(self, memberList, lastVisibility, itemCount,
- separator)
- if self.indent:
- memberString = CGIndenter(CGGeneric(memberString),
- len(self.indent)).define()
- result = result + memberString
-
- result = result + self.indent + '};\n'
- return result
-
- def define(self):
- def defineMembers(cgClass, memberList, itemCount, separator=''):
- result = ''
- for member in memberList:
- if itemCount != 0:
- result = result + separator
- result = result + member.define(cgClass)
- itemCount = itemCount + 1
- return (result, itemCount)
-
- order = [(self.members, '\n'), (self.constructors, '\n'),
- (self.methods, '\n')]
-
- result = ''
- itemCount = 0
- for (memberList, separator) in order:
- (memberString, itemCount) = defineMembers(self, memberList,
- itemCount, separator)
- result = result + memberString
- return result
-
-class CGResolveOwnProperty(CGAbstractMethod):
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
- Argument('jsid', 'id'), Argument('bool', 'set'),
- Argument('JSPropertyDescriptor*', 'desc')]
- CGAbstractMethod.__init__(self, descriptor, "ResolveOwnProperty", "bool", args)
- def definition_body(self):
- return """ JSObject* obj = wrapper;
- if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
- obj = js::UnwrapObject(obj);
- }
- // We rely on getOwnPropertyDescriptor not shadowing prototype properties by named
- // properties. If that changes we'll need to filter here.
- return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, set, desc);
-"""
-
-class CGEnumerateOwnProperties(CGAbstractMethod):
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
- Argument('JS::AutoIdVector&', 'props')]
- CGAbstractMethod.__init__(self, descriptor, "EnumerateOwnProperties", "bool", args)
- def definition_body(self):
- return """ JSObject* obj = wrapper;
- if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
- obj = js::UnwrapObject(obj);
- }
- // We rely on getOwnPropertyNames not shadowing prototype properties by named
- // properties. If that changes we'll need to filter here.
- return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);
-"""
-
-class CGXrayHelper(CGAbstractMethod):
- def __init__(self, descriptor, name, args, properties):
- CGAbstractMethod.__init__(self, descriptor, name, "bool", args)
- self.properties = properties
-
- def definition_body(self):
- varNames = self.properties.variableNames(True)
-
- methods = self.properties.methods
- if methods.hasNonChromeOnly() or methods.hasChromeOnly():
- methodArgs = """// %(methods)s has an end-of-list marker at the end that we ignore
-%(methods)s, %(methods)s_ids, %(methods)s_specs, ArrayLength(%(methods)s) - 1""" % varNames
- else:
- methodArgs = "NULL, NULL, NULL, 0"
- methodArgs = CGGeneric(methodArgs)
-
- attrs = self.properties.attrs
- if attrs.hasNonChromeOnly() or attrs.hasChromeOnly():
- attrArgs = """// %(attrs)s has an end-of-list marker at the end that we ignore
-%(attrs)s, %(attrs)s_ids, %(attrs)s_specs, ArrayLength(%(attrs)s) - 1""" % varNames
- else:
- attrArgs = "NULL, NULL, NULL, 0"
- attrArgs = CGGeneric(attrArgs)
-
- consts = self.properties.consts
- if consts.hasNonChromeOnly() or consts.hasChromeOnly():
- constArgs = """// %(consts)s has an end-of-list marker at the end that we ignore
-%(consts)s, %(consts)s_ids, %(consts)s_specs, ArrayLength(%(consts)s) - 1""" % varNames
- else:
- constArgs = "NULL, NULL, NULL, 0"
- constArgs = CGGeneric(constArgs)
-
- prefixArgs = CGGeneric(self.getPrefixArgs())
-
- return CGIndenter(
- CGWrapper(CGList([prefixArgs, methodArgs, attrArgs, constArgs], ",\n"),
- pre=("return Xray%s(" % self.name),
- post=");",
- reindent=True)).define()
-
-class CGResolveProperty(CGXrayHelper):
- def __init__(self, descriptor, properties):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
- Argument('jsid', 'id'), Argument('bool', 'set'),
- Argument('JSPropertyDescriptor*', 'desc')]
- CGXrayHelper.__init__(self, descriptor, "ResolveProperty", args,
- properties)
-
- def getPrefixArgs(self):
- return "cx, wrapper, id, desc"
-
-
-class CGEnumerateProperties(CGXrayHelper):
- def __init__(self, descriptor, properties):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'wrapper'),
- Argument('JS::AutoIdVector&', 'props')]
- CGXrayHelper.__init__(self, descriptor, "EnumerateProperties", args,
- properties)
-
- def getPrefixArgs(self):
- return "props"
-
-class CGPrototypeTraitsClass(CGClass):
- def __init__(self, descriptor, indent=''):
- templateArgs = [Argument('prototypes::ID', 'PrototypeID')]
- templateSpecialization = ['prototypes::id::' + descriptor.name]
- enums = [ClassEnum('', ['Depth'],
- [descriptor.interface.inheritanceDepth()])]
- typedefs = [ClassTypedef('NativeType', descriptor.nativeType)]
- CGClass.__init__(self, 'PrototypeTraits', indent=indent,
- templateArgs=templateArgs,
- templateSpecialization=templateSpecialization,
- enums=enums, typedefs=typedefs, isStruct=True)
-
-class CGPrototypeIDMapClass(CGClass):
- def __init__(self, descriptor, indent=''):
- templateArgs = [Argument('class', 'ConcreteClass')]
- templateSpecialization = [descriptor.nativeType]
- enums = [ClassEnum('', ['PrototypeID'],
- ['prototypes::id::' + descriptor.name])]
- CGClass.__init__(self, 'PrototypeIDMap', indent=indent,
- templateArgs=templateArgs,
- templateSpecialization=templateSpecialization,
- enums=enums, isStruct=True)
-
-class CGClassForwardDeclare(CGThing):
- def __init__(self, name, isStruct=False):
- CGThing.__init__(self)
- self.name = name
- self.isStruct = isStruct
- def declare(self):
- type = 'struct' if self.isStruct else 'class'
- return '%s %s;\n' % (type, self.name)
- def define(self):
- # Header only
- return ''
-
-class CGProxySpecialOperation(CGPerSignatureCall):
- """
- Base class for classes for calling an indexed or named special operation
- (don't use this directly, use the derived classes below).
- """
- def __init__(self, descriptor, operation):
- nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation))
- operation = descriptor.operations[operation]
- assert len(operation.signatures()) == 1
- signature = operation.signatures()[0]
- extendedAttributes = descriptor.getExtendedAttributes(operation)
-
- (returnType, arguments) = signature
-
- # We pass len(arguments) as the final argument so that the
- # CGPerSignatureCall won't do any argument conversion of its own.
- CGPerSignatureCall.__init__(self, returnType, "", arguments, nativeName,
- False, descriptor, operation,
- len(arguments))
-
- if operation.isSetter() or operation.isCreator():
- # arguments[0] is the index or name of the item that we're setting.
- argument = arguments[1]
- template = getJSToNativeConversionTemplate(argument.type, descriptor,
- treatNullAs=argument.treatNullAs,
- treatUndefinedAs=argument.treatUndefinedAs)
- templateValues = {
- "declName": argument.identifier.name,
- "holderName": argument.identifier.name + "_holder",
- "val": "desc->value",
- "valPtr": "&desc->value"
- }
- self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(template, templateValues))
- elif operation.isGetter():
- self.cgRoot.prepend(CGGeneric("bool found;"))
-
- def getArguments(self):
- args = [(a, a.identifier.name) for a in self.arguments]
- if self.idlNode.isGetter():
- args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean],
- self.idlNode),
- "found"))
- return args
-
- def wrap_return_value(self):
- if not self.idlNode.isGetter() or self.templateValues is None:
- return ""
-
- wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues))
- wrap = CGIfWrapper(wrap, "found")
- return "\n" + wrap.define()
-
-class CGProxyIndexedGetter(CGProxySpecialOperation):
- """
- Class to generate a call to an indexed getter. If templateValues is not None
- the returned value will be wrapped with wrapForType using templateValues.
- """
- def __init__(self, descriptor, templateValues=None):
- self.templateValues = templateValues
- CGProxySpecialOperation.__init__(self, descriptor, 'IndexedGetter')
-
-class CGProxyIndexedSetter(CGProxySpecialOperation):
- """
- Class to generate a call to an indexed setter.
- """
- def __init__(self, descriptor):
- CGProxySpecialOperation.__init__(self, descriptor, 'IndexedSetter')
-
-class CGProxyNamedGetter(CGProxySpecialOperation):
- """
- Class to generate a call to an named getter. If templateValues is not None
- the returned value will be wrapped with wrapForType using templateValues.
- """
- def __init__(self, descriptor, templateValues=None):
- self.templateValues = templateValues
- CGProxySpecialOperation.__init__(self, descriptor, 'NamedGetter')
-
-class CGProxyNamedSetter(CGProxySpecialOperation):
- """
- Class to generate a call to a named setter.
- """
- def __init__(self, descriptor):
- CGProxySpecialOperation.__init__(self, descriptor, 'NamedSetter')
-
-class CGProxyIsProxy(CGAbstractMethod):
- def __init__(self, descriptor):
- args = [Argument('JSObject*', 'obj')]
- CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True)
- def declare(self):
- return ""
- def definition_body(self):
- return " return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();"
-
-class CGProxyUnwrap(CGAbstractMethod):
- def __init__(self, descriptor):
- args = [Argument('JSObject*', 'obj')]
- CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", descriptor.nativeType + '*', args, alwaysInline=True)
- def declare(self):
- return ""
- def definition_body(self):
- return """ if (xpc::WrapperFactory::IsXrayWrapper(obj)) {
- obj = js::UnwrapObject(obj);
- }
- MOZ_ASSERT(IsProxy(obj));
- return static_cast<%s*>(js::GetProxyPrivate(obj).toPrivate());""" % (self.descriptor.nativeType)
-
-class CGDOMJSProxyHandlerDOMClass(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
- self.descriptor = descriptor
- def declare(self):
- return "extern const DOMClass Class;\n"
- def define(self):
- return """
-const DOMClass Class = """ + DOMClass(self.descriptor) + """;
-
-"""
-
-class CGDOMJSProxyHandler_CGDOMJSProxyHandler(ClassConstructor):
- def __init__(self):
- ClassConstructor.__init__(self, [], inline=True, visibility="private",
- baseConstructors=["mozilla::dom::DOMProxyHandler(Class)"],
- body="")
-
-class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
- Argument('jsid', 'id'), Argument('bool', 'set'),
- Argument('JSPropertyDescriptor*', 'desc')]
- ClassMethod.__init__(self, "getOwnPropertyDescriptor", "bool", args)
- self.descriptor = descriptor
- def getBody(self):
- indexedGetter = self.descriptor.operations['IndexedGetter']
- indexedSetter = self.descriptor.operations['IndexedSetter']
-
- setOrIndexedGet = ""
- if indexedGetter or indexedSetter:
- setOrIndexedGet += "int32_t index = GetArrayIndexFromId(cx, id);\n"
-
- if indexedGetter:
- readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None)
- fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
- templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value',
- 'obj': 'proxy', 'successCode': fillDescriptor}
- get = ("if (index >= 0) {\n" +
- " %s* self = UnwrapProxy(proxy);\n" +
- CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
- "}\n") % (self.descriptor.nativeType)
-
- if indexedSetter or self.descriptor.operations['NamedSetter']:
- setOrIndexedGet += "if (set) {\n"
- if indexedSetter:
- setOrIndexedGet += (" if (index >= 0) {\n")
- if not 'IndexedCreator' in self.descriptor.operations:
- # FIXME need to check that this is a 'supported property index'
- assert False
- setOrIndexedGet += (" FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
- " return true;\n" +
- " }\n")
- if self.descriptor.operations['NamedSetter']:
- setOrIndexedGet += " if (JSID_IS_STRING(id)) {\n"
- if not 'NamedCreator' in self.descriptor.operations:
- # FIXME need to check that this is a 'supported property name'
- assert False
- setOrIndexedGet += (" FillPropertyDescriptor(desc, proxy, JSVAL_VOID, false);\n" +
- " return true;\n" +
- " }\n")
- setOrIndexedGet += "}"
- if indexedGetter:
- setOrIndexedGet += (" else {\n" +
- CGIndenter(CGGeneric(get)).define() +
- "}")
- setOrIndexedGet += "\n\n"
- elif indexedGetter:
- setOrIndexedGet += ("if (!set) {\n" +
- CGIndenter(CGGeneric(get)).define() +
- "}\n\n")
-
- namedGetter = self.descriptor.operations['NamedGetter']
- if namedGetter:
- readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
- fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
- templateValues = {'jsvalRef': 'desc->value', 'jsvalPtr': '&desc->value',
- 'obj': 'proxy', 'successCode': fillDescriptor}
- # Once we start supporting OverrideBuiltins we need to make
- # ResolveOwnProperty or EnumerateOwnProperties filter out named
- # properties that shadow prototype properties.
- namedGet = ("\n" +
- "if (!set && JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
- " JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
- " FakeDependentString name;\n"
- " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
- " eStringify, eStringify, name)) {\n" +
- " return false;\n" +
- " }\n" +
- "\n" +
- " %s* self = UnwrapProxy(proxy);\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" +
- "}\n") % (self.descriptor.nativeType)
- else:
- namedGet = ""
-
- return setOrIndexedGet + """JSObject* expando;
-if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
- unsigned flags = (set ? JSRESOLVE_ASSIGNING : 0) | JSRESOLVE_QUALIFIED;
- if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) {
- return false;
- }
- if (desc->obj) {
- // Pretend the property lives on the wrapper.
- desc->obj = proxy;
- return true;
- }
-}
-""" + namedGet + """
-desc->obj = NULL;
-return true;"""
-
-class CGDOMJSProxyHandler_defineProperty(ClassMethod):
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
- Argument('jsid', 'id'),
- Argument('JSPropertyDescriptor*', 'desc')]
- ClassMethod.__init__(self, "defineProperty", "bool", args)
- self.descriptor = descriptor
- def getBody(self):
- set = ""
-
- indexedSetter = self.descriptor.operations['IndexedSetter']
- if indexedSetter:
- if not (self.descriptor.operations['IndexedCreator'] is indexedSetter):
- raise TypeError("Can't handle creator that's different from the setter")
- set += ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
- "if (index >= 0) {\n" +
- " %s* self = UnwrapProxy(proxy);\n" +
- CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
- " return true;\n" +
- "}\n") % (self.descriptor.nativeType)
- elif self.descriptor.operations['IndexedGetter']:
- set += ("if (GetArrayIndexFromId(cx, id) >= 0) {\n" +
- " return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
- "}\n") % self.descriptor.name
-
- namedSetter = self.descriptor.operations['NamedSetter']
- if namedSetter:
- if not self.descriptor.operations['NamedCreator'] is namedSetter:
- raise TypeError("Can't handle creator that's different from the setter")
- set += ("if (JSID_IS_STRING(id)) {\n" +
- " JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
- " FakeDependentString name;\n"
- " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
- " eStringify, eStringify, name)) {\n" +
- " return false;\n" +
- " }\n" +
- "\n" +
- " %s* self = UnwrapProxy(proxy);\n" +
- CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + "\n" +
- "}\n") % (self.descriptor.nativeType)
- elif self.descriptor.operations['NamedGetter']:
- set += ("if (JSID_IS_STRING(id)) {\n" +
- " JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
- " FakeDependentString name;\n"
- " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
- " eStringify, eStringify, name)) {\n" +
- " return false;\n" +
- " }\n" +
- " %s* self = UnwrapProxy(proxy);\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
- " if (found) {\n"
- " return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
- " }\n" +
- " return true;\n"
- "}\n") % (self.descriptor.nativeType, self.descriptor.name)
- return set + """return mozilla::dom::DOMProxyHandler::defineProperty(%s);""" % ", ".join(a.name for a in self.args)
-
-class CGDOMJSProxyHandler_getOwnPropertyNames(ClassMethod):
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
- Argument('JS::AutoIdVector&', 'props')]
- ClassMethod.__init__(self, "getOwnPropertyNames", "bool", args)
- self.descriptor = descriptor
- def getBody(self):
- indexedGetter = self.descriptor.operations['IndexedGetter']
- if indexedGetter:
- addIndices = """uint32_t length = UnwrapProxy(proxy)->Length();
-MOZ_ASSERT(int32_t(length) >= 0);
-for (int32_t i = 0; i < int32_t(length); ++i) {
- if (!props.append(INT_TO_JSID(i))) {
- return false;
- }
-}
-
-"""
- else:
- addIndices = ""
-
- return addIndices + """JSObject* expando;
-if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = DOMProxyHandler::GetExpandoObject(proxy)) &&
- !js::GetPropertyNames(cx, expando, JSITER_OWNONLY | JSITER_HIDDEN, &props)) {
- return false;
-}
-
-// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=772869 Add named items
-return true;"""
-
-class CGDOMJSProxyHandler_hasOwn(ClassMethod):
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
- Argument('jsid', 'id'), Argument('bool*', 'bp')]
- ClassMethod.__init__(self, "hasOwn", "bool", args)
- self.descriptor = descriptor
- def getBody(self):
- indexedGetter = self.descriptor.operations['IndexedGetter']
- if indexedGetter:
- indexed = ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
- "if (index >= 0) {\n" +
- " %s* self = UnwrapProxy(proxy);\n" +
- CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
- " *bp = found;\n" +
- " return true;\n" +
- "}\n\n") % (self.descriptor.nativeType)
- else:
- indexed = ""
-
- namedGetter = self.descriptor.operations['NamedGetter']
- if namedGetter:
- named = ("if (JSID_IS_STRING(id) && !HasPropertyOnPrototype(cx, proxy, this, id)) {\n" +
- " jsval nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
- " FakeDependentString name;\n"
- " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
- " eStringify, eStringify, name)) {\n" +
- " return false;\n" +
- " }\n" +
- "\n" +
- " %s* self = UnwrapProxy(proxy);\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" +
- " *bp = found;\n"
- " return true;\n"
- "}\n" +
- "\n") % (self.descriptor.nativeType)
- else:
- named = ""
-
- return indexed + """JSObject* expando = GetExpandoObject(proxy);
-if (expando) {
- JSBool b = true;
- JSBool ok = JS_HasPropertyById(cx, expando, id, &b);
- *bp = !!b;
- if (!ok || *bp) {
- return ok;
- }
-}
-
-""" + named + """*bp = false;
-return true;"""
-
-class CGDOMJSProxyHandler_get(ClassMethod):
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
- Argument('JSObject*', 'receiver'), Argument('jsid', 'id'),
- Argument('JS::Value*', 'vp')]
- ClassMethod.__init__(self, "get", "bool", args)
- self.descriptor = descriptor
- def getBody(self):
- getFromExpando = """JSObject* expando = DOMProxyHandler::GetExpandoObject(proxy);
-if (expando) {
- JSBool hasProp;
- if (!JS_HasPropertyById(cx, expando, id, &hasProp)) {
- return false;
- }
-
- if (hasProp) {
- return JS_GetPropertyById(cx, expando, id, vp);
- }
-}"""
-
- templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp', 'obj': 'proxy'}
-
- indexedGetter = self.descriptor.operations['IndexedGetter']
- if indexedGetter:
- getIndexedOrExpando = ("int32_t index = GetArrayIndexFromId(cx, id);\n" +
- "if (index >= 0) {\n" +
- " %s* self = UnwrapProxy(proxy);\n" +
- CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define()) % (self.descriptor.nativeType)
- getIndexedOrExpando += """
- // Even if we don't have this index, we don't forward the
- // get on to our expando object.
-} else {
- %s
-}
-""" % (stripTrailingWhitespace(getFromExpando.replace('\n', '\n ')))
- else:
- getIndexedOrExpando = getFromExpando + "\n"
-
- namedGetter = self.descriptor.operations['NamedGetter']
- if namedGetter:
- getNamed = ("if (JSID_IS_STRING(id)) {\n" +
- " JS::Value nameVal = STRING_TO_JSVAL(JSID_TO_STRING(id));\n" +
- " FakeDependentString name;\n"
- " if (!ConvertJSValueToString(cx, nameVal, &nameVal,\n" +
- " eStringify, eStringify, name)) {\n" +
- " return false;\n" +
- " }\n" +
- "\n" +
- " %s* self = UnwrapProxy(proxy);\n" +
- CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
- "}\n") % (self.descriptor.nativeType)
- else:
- getNamed = ""
-
- return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
- "Should not have a XrayWrapper here");
-
-%s
-bool found;
-if (!GetPropertyOnPrototype(cx, proxy, id, &found, vp)) {
- return false;
-}
-
-if (found) {
- return true;
-}
-%s
-vp->setUndefined();
-return true;""" % (getIndexedOrExpando, getNamed)
-
-class CGDOMJSProxyHandler_obj_toString(ClassMethod):
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy')]
- ClassMethod.__init__(self, "obj_toString", "JSString*", args)
- self.descriptor = descriptor
- def getBody(self):
- stringifier = self.descriptor.operations['Stringifier']
- if stringifier:
- name = stringifier.identifier.name
- nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
- signature = stringifier.signatures()[0]
- returnType = signature[0]
- extendedAttributes = self.descriptor.getExtendedAttributes(stringifier)
- infallible = 'infallible' in extendedAttributes
- if not infallible:
- error = CGGeneric(
- ('ThrowMethodFailedWithDetails(cx, rv, "%s", "toString");\n' +
- "return NULL;") % self.descriptor.interface.identifier.name)
- else:
- error = None
- call = CGCallGenerator(error, [], "", returnType, extendedAttributes, self.descriptor, nativeName, False, object="UnwrapProxy(proxy)")
- return call.define() + """
-
-JSString* jsresult;
-return xpc_qsStringToJsstring(cx, result, &jsresult) ? jsresult : NULL;"""
-
- return "return mozilla::dom::DOMProxyHandler::obj_toString(cx, \"%s\");" % self.descriptor.name
-
-class CGDOMJSProxyHandler_finalize(ClassMethod):
- def __init__(self, descriptor):
- args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')]
- ClassMethod.__init__(self, "finalize", "void", args)
- self.descriptor = descriptor
- def getBody(self):
- return ("%s self = UnwrapProxy(proxy);\n\n" % (self.descriptor.nativeType + "*") +
- finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name))
-
-class CGDOMJSProxyHandler_getElementIfPresent(ClassMethod):
- def __init__(self, descriptor):
- args = [Argument('JSContext*', 'cx'), Argument('JSObject*', 'proxy'),
- Argument('JSObject*', 'receiver'),
- Argument('uint32_t', 'index'),
- Argument('JS::Value*', 'vp'), Argument('bool*', 'present')]
- ClassMethod.__init__(self, "getElementIfPresent", "bool", args)
- self.descriptor = descriptor
- def getBody(self):
- indexedGetter = self.descriptor.operations['IndexedGetter']
- if indexedGetter:
- successCode = """*present = found;
-return true;"""
- templateValues = {'jsvalRef': '*vp', 'jsvalPtr': 'vp',
- 'obj': 'proxy', 'successCode': successCode}
- get = ("%s* self = UnwrapProxy(proxy);\n" +
- CGProxyIndexedGetter(self.descriptor, templateValues).define() + "\n"
- "// We skip the expando object if there is an indexed getter.\n" +
- "\n") % (self.descriptor.nativeType)
- else:
- get = """
-
-JSObject* expando = GetExpandoObject(proxy);
-if (expando) {
- JSBool isPresent;
- if (!JS_GetElementIfPresent(cx, expando, index, expando, vp, &isPresent)) {
- return false;
- }
- if (isPresent) {
- *present = true;
- return true;
- }
-}
-"""
-
- return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
- "Should not have a XrayWrapper here");
-
-""" + get + """
-// No need to worry about name getters here, so just check the proto.
-
-JSObject *proto;
-if (!js::GetObjectProto(cx, proxy, &proto)) {
- return false;
-}
-if (proto) {
- JSBool isPresent;
- if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent)) {
- return false;
- }
- *present = isPresent;
- return true;
-}
-
-*present = false;
-// Can't Debug_SetValueRangeToCrashOnTouch because it's not public
-return true;"""
-
-class CGDOMJSProxyHandler_getInstance(ClassMethod):
- def __init__(self):
- ClassMethod.__init__(self, "getInstance", "DOMProxyHandler*", [], static=True)
- def getBody(self):
- return """static DOMProxyHandler instance;
-return &instance;"""
-
-class CGDOMJSProxyHandler(CGClass):
- def __init__(self, descriptor):
- constructors = [CGDOMJSProxyHandler_CGDOMJSProxyHandler()]
- methods = [CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor)]
- if descriptor.operations['IndexedSetter'] or descriptor.operations['NamedSetter']:
- methods.append(CGDOMJSProxyHandler_defineProperty(descriptor))
- methods.extend([CGDOMJSProxyHandler_getOwnPropertyNames(descriptor),
- CGDOMJSProxyHandler_hasOwn(descriptor),
- CGDOMJSProxyHandler_get(descriptor),
- CGDOMJSProxyHandler_obj_toString(descriptor),
- CGDOMJSProxyHandler_finalize(descriptor),
- CGDOMJSProxyHandler_getElementIfPresent(descriptor),
- CGDOMJSProxyHandler_getInstance()])
- CGClass.__init__(self, 'DOMProxyHandler',
- bases=[ClassBase('mozilla::dom::DOMProxyHandler')],
- constructors=constructors,
- methods=methods)
-
-def stripTrailingWhitespace(text):
- tail = '\n' if text.endswith('\n') else ''
- lines = text.splitlines()
- for i in range(len(lines)):
- lines[i] = lines[i].rstrip()
- return '\n'.join(lines) + tail
-
-class CGDescriptor(CGThing):
- def __init__(self, descriptor):
- CGThing.__init__(self)
-
- assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject()
-
- cgThings = []
- if descriptor.interface.hasInterfacePrototypeObject():
- (hasMethod, hasGetter, hasLenientGetter,
- hasSetter, hasLenientSetter) = False, False, False, False, False
- for m in descriptor.interface.members:
- if m.isMethod() and not m.isStatic() and not m.isIdentifierLess():
- cgThings.append(CGSpecializedMethod(descriptor, m))
- cgThings.append(CGMemberJITInfo(descriptor, m))
- hasMethod = True
- elif m.isAttr():
- cgThings.append(CGSpecializedGetter(descriptor, m))
- if m.hasLenientThis():
- hasLenientGetter = True
- else:
- hasGetter = True
- if not m.readonly:
- cgThings.append(CGSpecializedSetter(descriptor, m))
- if m.hasLenientThis():
- hasLenientSetter = True
- else:
- hasSetter = True
- cgThings.append(CGMemberJITInfo(descriptor, m))
- if hasMethod: cgThings.append(CGGenericMethod(descriptor))
- if hasGetter: cgThings.append(CGGenericGetter(descriptor))
- if hasLenientGetter: cgThings.append(CGGenericGetter(descriptor,
- lenientThis=True))
- if hasSetter: cgThings.append(CGGenericSetter(descriptor))
- if hasLenientSetter: cgThings.append(CGGenericSetter(descriptor,
- lenientThis=True))
-
- if descriptor.concrete and not descriptor.proxy:
- if not descriptor.workers and descriptor.wrapperCache:
- cgThings.append(CGAddPropertyHook(descriptor))
-
- # Always have a finalize hook, regardless of whether the class wants a
- # custom hook.
- cgThings.append(CGClassFinalizeHook(descriptor))
-
- # Only generate a trace hook if the class wants a custom hook.
- if (descriptor.customTrace):
- cgThings.append(CGClassTraceHook(descriptor))
-
- if descriptor.interface.hasInterfaceObject():
- cgThings.append(CGClassConstructHook(descriptor))
- cgThings.append(CGClassHasInstanceHook(descriptor))
- cgThings.append(CGInterfaceObjectJSClass(descriptor))
-
- if descriptor.interface.hasInterfacePrototypeObject():
- cgThings.append(CGPrototypeJSClass(descriptor))
-
- properties = PropertyArrays(descriptor)
- cgThings.append(CGGeneric(define=str(properties)))
- cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties))
- if descriptor.interface.hasInterfacePrototypeObject():
- cgThings.append(CGGetProtoObjectMethod(descriptor))
- else:
- cgThings.append(CGGetConstructorObjectMethod(descriptor))
-
- # Set up our Xray callbacks as needed. Note that we don't need to do
- # it in workers.
- if (descriptor.interface.hasInterfacePrototypeObject() and
- not descriptor.workers):
- if descriptor.concrete and descriptor.proxy:
- cgThings.append(CGResolveOwnProperty(descriptor))
- cgThings.append(CGEnumerateOwnProperties(descriptor))
- cgThings.append(CGResolveProperty(descriptor, properties))
- cgThings.append(CGEnumerateProperties(descriptor, properties))
-
- if descriptor.interface.hasInterfaceObject():
- cgThings.append(CGDefineDOMInterfaceMethod(descriptor))
- if (not descriptor.interface.isExternal() and
- # Workers stuff is never pref-controlled
- not descriptor.workers and
- descriptor.interface.getExtendedAttribute("PrefControlled") is not None):
- cgThings.append(CGPrefEnabled(descriptor))
-
- if descriptor.interface.hasInterfacePrototypeObject():
- cgThings.append(CGNativePropertyHooks(descriptor))
-
- if descriptor.concrete:
- if descriptor.proxy:
- cgThings.append(CGProxyIsProxy(descriptor))
- cgThings.append(CGProxyUnwrap(descriptor))
- cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
- cgThings.append(CGDOMJSProxyHandler(descriptor))
- cgThings.append(CGIsMethod(descriptor))
- else:
- cgThings.append(CGDOMJSClass(descriptor))
-
- if descriptor.wrapperCache:
- cgThings.append(CGWrapWithCacheMethod(descriptor))
- cgThings.append(CGWrapMethod(descriptor))
- else:
- cgThings.append(CGWrapNonWrapperCacheMethod(descriptor))
-
- cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n")
- cgThings = CGWrapper(cgThings, pre='\n', post='\n')
- self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name),
- cgThings),
- post='\n')
-
- def declare(self):
- return self.cgRoot.declare()
- def define(self):
- return self.cgRoot.define()
-
-class CGNamespacedEnum(CGThing):
- def __init__(self, namespace, enumName, names, values, comment=""):
-
- if not values:
- values = []
-
- # Account for explicit enum values.
- entries = []
- for i in range(0, len(names)):
- if len(values) > i and values[i] is not None:
- entry = "%s = %s" % (names[i], values[i])
- else:
- entry = names[i]
- entries.append(entry)
-
- # Append a Count.
- entries.append('_' + enumName + '_Count')
-
- # Indent.
- entries = [' ' + e for e in entries]
-
- # Build the enum body.
- enumstr = comment + 'enum %s\n{\n%s\n};\n' % (enumName, ',\n'.join(entries))
- curr = CGGeneric(declare=enumstr)
-
- # Add some whitespace padding.
- curr = CGWrapper(curr, pre='\n',post='\n')
-
- # Add the namespace.
- curr = CGNamespace(namespace, curr)
-
- # Add the typedef
- typedef = '\ntypedef %s::%s %s;\n\n' % (namespace, enumName, enumName)
- curr = CGList([curr, CGGeneric(declare=typedef)])
-
- # Save the result.
- self.node = curr
-
- def declare(self):
- return self.node.declare()
- def define(self):
- assert False # Only for headers.
-
-class CGDictionary(CGThing):
- def __init__(self, dictionary, descriptorProvider):
- self.dictionary = dictionary;
- self.workers = descriptorProvider.workers
- if all(CGDictionary(d, descriptorProvider).generatable for
- d in CGDictionary.getDictionaryDependencies(dictionary)):
- self.generatable = True
- else:
- self.generatable = False
- # Nothing else to do here
- return
- # Getting a conversion template for interface types can fail
- # if we don't have a relevant descriptor when self.workers is True.
- # If that happens, just mark ourselves as not being
- # generatable and move on.
- try:
- self.memberInfo = [
- (member,
- getJSToNativeConversionTemplate(member.type,
- descriptorProvider,
- isMember=True,
- isOptional=(not member.defaultValue),
- defaultValue=member.defaultValue))
- for member in dictionary.members ]
- except NoSuchDescriptorError, err:
- if not self.workers:
- raise err
- self.generatable = False
-
- def declare(self):
- if not self.generatable:
- return ""
- d = self.dictionary
- if d.parent:
- inheritance = ": public %s " % self.makeClassName(d.parent)
- else:
- inheritance = ""
- memberDecls = [" %s %s;" %
- (self.getMemberType(m), m[0].identifier.name)
- for m in self.memberInfo]
-
- return (string.Template(
- "struct ${selfName} ${inheritance}{\n"
- " ${selfName}() {}\n"
- " bool Init(JSContext* cx, const JS::Value& val);\n"
- "\n" +
- "\n".join(memberDecls) + "\n"
- "private:\n"
- " // Disallow copy-construction\n"
- " ${selfName}(const ${selfName}&) MOZ_DELETE;\n" +
- # NOTE: jsids are per-runtime, so don't use them in workers
- (" static bool InitIds(JSContext* cx);\n"
- " static bool initedIds;\n" if not self.workers else "") +
- "\n".join(" static jsid " +
- self.makeIdName(m.identifier.name) + ";" for
- m in d.members) + "\n"
- "};").substitute( { "selfName": self.makeClassName(d),
- "inheritance": inheritance }))
-
- def define(self):
- if not self.generatable:
- return ""
- d = self.dictionary
- if d.parent:
- initParent = ("// Per spec, we init the parent's members first\n"
- "if (!%s::Init(cx, val)) {\n"
- " return false;\n"
- "}\n" % self.makeClassName(d.parent))
- else:
- initParent = ""
-
- memberInits = [CGIndenter(self.getMemberConversion(m)).define()
- for m in self.memberInfo]
- idinit = [CGGeneric('!InternJSString(cx, %s, "%s")' %
- (m.identifier.name + "_id", m.identifier.name))
- for m in d.members]
- idinit = CGList(idinit, " ||\n")
- idinit = CGWrapper(idinit, pre="if (",
- post=(") {\n"
- " return false;\n"
- "}"),
- reindent=True)
-
- return string.Template(
- # NOTE: jsids are per-runtime, so don't use them in workers
- ("bool ${selfName}::initedIds = false;\n" +
- "\n".join("jsid ${selfName}::%s = JSID_VOID;" %
- self.makeIdName(m.identifier.name)
- for m in d.members) + "\n"
- "\n"
- "bool\n"
- "${selfName}::InitIds(JSContext* cx)\n"
- "{\n"
- " MOZ_ASSERT(!initedIds);\n"
- "${idInit}\n"
- " initedIds = true;\n"
- " return true;\n"
- "}\n"
- "\n" if not self.workers else "") +
- "bool\n"
- "${selfName}::Init(JSContext* cx, const JS::Value& val)\n"
- "{\n" +
- # NOTE: jsids are per-runtime, so don't use them in workers
- (" if (!initedIds && !InitIds(cx)) {\n"
- " return false;\n"
- " }\n" if not self.workers else "") +
- "${initParent}"
- " JSBool found;\n"
- " JS::Value temp;\n"
- " bool isNull = val.isNullOrUndefined();\n"
- " if (!isNull && !val.isObject()) {\n"
- " return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
- " }\n"
- "\n"
- "${initMembers}\n"
- " return true;\n"
- "}").substitute({
- "selfName": self.makeClassName(d),
- "initParent": CGIndenter(CGGeneric(initParent)).define(),
- "initMembers": "\n\n".join(memberInits),
- "idInit": CGIndenter(idinit).define(),
- "isMainThread": toStringBool(not self.workers)
- })
-
- @staticmethod
- def makeDictionaryName(dictionary, workers):
- suffix = "Workers" if workers else ""
- return dictionary.identifier.name + suffix
-
- def makeClassName(self, dictionary):
- return self.makeDictionaryName(dictionary, self.workers)
-
- def getMemberType(self, memberInfo):
- (member, (templateBody, declType,
- holderType, dealWithOptional)) = memberInfo
- # We can't handle having a holderType here
- assert holderType is None
- if dealWithOptional:
- declType = CGWrapper(declType, pre="Optional< ", post=" >")
- return declType.define()
-
- def getMemberConversion(self, memberInfo):
- (member, (templateBody, declType,
- holderType, dealWithOptional)) = memberInfo
- replacements = { "val": "temp",
- "valPtr": "&temp",
- # Use this->%s to refer to members, because we don't
- # control the member names and want to make sure we're
- # talking about the member, not some local that
- # shadows the member. Another option would be to move
- # the guts of init to a static method which is passed
- # an explicit reference to our dictionary object, so
- # we couldn't screw this up even if we wanted to....
- "declName": ("(this->%s)" % member.identifier.name),
- # We need a holder name for external interfaces, but
- # it's scoped down to the conversion so we can just use
- # anything we want.
- "holderName": "holder"}
- # We can't handle having a holderType here
- assert holderType is None
- if dealWithOptional:
- replacements["declName"] = "(" + replacements["declName"] + ".Value())"
- if member.defaultValue:
- replacements["haveValue"] = "found"
-
- # NOTE: jsids are per-runtime, so don't use them in workers
- if self.workers:
- propName = member.identifier.name
- propCheck = ('JS_HasProperty(cx, &val.toObject(), "%s", &found)' %
- propName)
- propGet = ('JS_GetProperty(cx, &val.toObject(), "%s", &temp)' %
- propName)
- else:
- propId = self.makeIdName(member.identifier.name);
- propCheck = ("JS_HasPropertyById(cx, &val.toObject(), %s, &found)" %
- propId)
- propGet = ("JS_GetPropertyById(cx, &val.toObject(), %s, &temp)" %
- propId)
-
- conversionReplacements = {
- "prop": "(this->%s)" % member.identifier.name,
- "convert": string.Template(templateBody).substitute(replacements),
- "propCheck": propCheck,
- "propGet": propGet
- }
- conversion = ("if (isNull) {\n"
- " found = false;\n"
- "} else if (!${propCheck}) {\n"
- " return false;\n"
- "}\n")
- if member.defaultValue:
- conversion += (
- "if (found) {\n"
- " if (!${propGet}) {\n"
- " return false;\n"
- " }\n"
- "}\n"
- "${convert}")
- else:
- conversion += (
- "if (found) {\n"
- " ${prop}.Construct();\n"
- " if (!${propGet}) {\n"
- " return false;\n"
- " }\n"
- "${convert}\n"
- "}")
- conversionReplacements["convert"] = CGIndenter(
- CGGeneric(conversionReplacements["convert"])).define()
-
- return CGGeneric(
- string.Template(conversion).substitute(conversionReplacements)
- )
-
- @staticmethod
- def makeIdName(name):
- return name + "_id"
-
- @staticmethod
- def getDictionaryDependencies(dictionary):
- deps = set();
- if dictionary.parent:
- deps.add(dictionary.parent)
- for member in dictionary.members:
- if member.type.isDictionary():
- deps.add(member.type.unroll().inner)
- return deps
-
-
-class CGRegisterProtos(CGAbstractMethod):
- def __init__(self, config):
- CGAbstractMethod.__init__(self, None, 'Register', 'void',
- [Argument('nsScriptNameSpaceManager*', 'aNameSpaceManager')])
- self.config = config
-
- def _defineMacro(self):
- return """
-#define REGISTER_PROTO(_dom_class, _pref_check) \\
- aNameSpaceManager->RegisterDefineDOMInterface(NS_LITERAL_STRING(#_dom_class), _dom_class##Binding::DefineDOMInterface, _pref_check);\n\n"""
- def _undefineMacro(self):
- return "\n#undef REGISTER_PROTO"
- def _registerProtos(self):
- def getPrefCheck(desc):
- if desc.interface.getExtendedAttribute("PrefControlled") is None:
- return "nullptr"
- return "%sBinding::PrefEnabled" % desc.name
- lines = ["REGISTER_PROTO(%s, %s);" % (desc.name, getPrefCheck(desc))
- for desc in self.config.getDescriptors(hasInterfaceObject=True,
- isExternal=False,
- workers=False,
- register=True)]
- return '\n'.join(lines) + '\n'
- def definition_body(self):
- return self._defineMacro() + self._registerProtos() + self._undefineMacro()
-
-class CGBindingRoot(CGThing):
- """
- Root codegen class for binding generation. Instantiate the class, and call
- declare or define to generate header or cpp code (respectively).
- """
- def __init__(self, config, prefix, webIDLFile):
- descriptors = config.getDescriptors(webIDLFile=webIDLFile,
- hasInterfaceOrInterfacePrototypeObject=True)
- dictionaries = config.getDictionaries(webIDLFile)
-
- forwardDeclares = [CGClassForwardDeclare('XPCWrappedNativeScope')]
-
- descriptorsForForwardDeclaration = list(descriptors)
- for dictionary in dictionaries:
- curDict = dictionary
- ifacemembers = []
- while curDict:
- ifacemembers.extend([m.type.unroll().inner for m
- in curDict.members
- if m.type.unroll().isInterface()])
- curDict = curDict.parent
- # Put in all the non-worker descriptors
- descriptorsForForwardDeclaration.extend(
- [config.getDescriptor(iface.identifier.name, False) for
- iface in ifacemembers])
- # And now the worker ones. But these may not exist, so we
- # have to be more careful.
- for iface in ifacemembers:
- try:
- descriptorsForForwardDeclaration.append(
- config.getDescriptor(iface.identifier.name, True))
- except NoSuchDescriptorError:
- # just move along
- pass
-
- for x in descriptorsForForwardDeclaration:
- nativeType = x.nativeType
- components = x.nativeType.split('::')
- className = components[-1]
- # JSObject is a struct, not a class
- declare = CGClassForwardDeclare(className, className is "JSObject")
- if len(components) > 1:
- declare = CGNamespace.build(components[:-1],
- CGWrapper(declare, declarePre='\n',
- declarePost='\n'),
- declareOnly=True)
- forwardDeclares.append(CGWrapper(declare, declarePost='\n'))
-
- forwardDeclares = CGList(forwardDeclares)
-
- descriptorsWithPrototype = filter(lambda d: d.interface.hasInterfacePrototypeObject(),
- descriptors)
- traitsClasses = [CGPrototypeTraitsClass(d) for d in descriptorsWithPrototype]
-
- # We must have a 1:1 mapping here, skip for prototypes that have more
- # than one concrete class implementation.
- traitsClasses.extend([CGPrototypeIDMapClass(d) for d in descriptorsWithPrototype
- if d.uniqueImplementation])
-
- # Wrap all of that in our namespaces.
- if len(traitsClasses) > 0:
- traitsClasses = CGNamespace.build(['mozilla', 'dom'],
- CGWrapper(CGList(traitsClasses),
- declarePre='\n'),
- declareOnly=True)
- traitsClasses = CGWrapper(traitsClasses, declarePost='\n')
- else:
- traitsClasses = None
-
- # Do codegen for all the enums
- def makeEnum(e):
- return CGNamespace.build([e.identifier.name + "Values"],
- CGEnum(e))
- def makeEnumTypedef(e):
- return CGGeneric(declare=("typedef %sValues::valuelist %s;\n" %
- (e.identifier.name, e.identifier.name)))
- cgthings = [ fun(e) for e in config.getEnums(webIDLFile)
- for fun in [makeEnum, makeEnumTypedef] ]
-
- # Do codegen for all the dictionaries. We have to be a bit careful
- # here, because we have to generate these in order from least derived
- # to most derived so that class inheritance works out. We also have to
- # generate members before the dictionary that contains them.
- #
- # XXXbz this will fail if we have two webidl files A and B such that A
- # declares a dictionary which inherits from a dictionary in B and B
- # declares a dictionary (possibly a different one!) that inherits from a
- # dictionary in A. The good news is that I expect this to never happen.
- reSortedDictionaries = []
- dictionaries = set(dictionaries)
- while len(dictionaries) != 0:
- # Find the dictionaries that don't depend on anything else anymore
- # and move them over.
- toMove = [d for d in dictionaries if
- len(CGDictionary.getDictionaryDependencies(d) &
- dictionaries) == 0]
- if len(toMove) == 0:
- raise TypeError("Loop in dictionary dependency graph")
- dictionaries = dictionaries - set(toMove)
- reSortedDictionaries.extend(toMove)
-
- dictionaries = reSortedDictionaries
- cgthings.extend([CGDictionary(d, config.getDescriptorProvider(True))
- for d in dictionaries])
- cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False))
- for d in dictionaries])
-
- # Do codegen for all the descriptors
- cgthings.extend([CGDescriptor(x) for x in descriptors])
-
- # And make sure we have the right number of newlines at the end
- curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n")
-
- # Wrap all of that in our namespaces.
- curr = CGNamespace.build(['mozilla', 'dom'],
- CGWrapper(curr, pre="\n"))
-
- curr = CGList([forwardDeclares,
- CGWrapper(CGGeneric("using namespace mozilla::dom;"),
- defineOnly=True),
- traitsClasses, curr],
- "\n")
-
- # Add header includes.
- curr = CGHeaders(descriptors,
- dictionaries,
- ['mozilla/dom/BindingUtils.h',
- 'mozilla/dom/DOMJSClass.h',
- 'mozilla/dom/DOMJSProxyHandler.h'],
- ['mozilla/dom/Nullable.h',
- 'PrimitiveConversions.h',
- 'XPCQuickStubs.h',
- 'nsDOMQS.h',
- 'AccessCheck.h',
- 'WorkerPrivate.h',
- 'nsContentUtils.h',
- 'mozilla/Preferences.h',
- # Have to include nsDOMQS.h to get fast arg unwrapping
- # for old-binding things with castability.
- 'nsDOMQS.h'
- ],
- curr)
-
- # Add include guards.
- curr = CGIncludeGuard(prefix, curr)
-
- # Add the auto-generated comment.
- curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
-
- # Store the final result.
- self.root = curr
-
- def declare(self):
- return stripTrailingWhitespace(self.root.declare())
- def define(self):
- return stripTrailingWhitespace(self.root.define())
-
-
-class GlobalGenRoots():
- """
- Roots for global codegen.
-
- To generate code, call the method associated with the target, and then
- call the appropriate define/declare method.
- """
-
- @staticmethod
- def PrototypeList(config):
-
- # Prototype ID enum.
- protos = [d.name for d in config.getDescriptors(hasInterfacePrototypeObject=True)]
- idEnum = CGNamespacedEnum('id', 'ID', protos, [0])
- idEnum = CGList([idEnum])
- idEnum.append(CGGeneric(declare="const unsigned MaxProtoChainLength = " +
- str(config.maxProtoChainLength) + ";\n\n"))
-
- # Wrap all of that in our namespaces.
- idEnum = CGNamespace.build(['mozilla', 'dom', 'prototypes'],
- CGWrapper(idEnum, pre='\n'))
- idEnum = CGWrapper(idEnum, post='\n')
-
- curr = CGList([idEnum])
-
- # Constructor ID enum.
- constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True,
- hasInterfacePrototypeObject=False)]
- idEnum = CGNamespacedEnum('id', 'ID', constructors, [0])
-
- # Wrap all of that in our namespaces.
- idEnum = CGNamespace.build(['mozilla', 'dom', 'constructors'],
- CGWrapper(idEnum, pre='\n'))
- idEnum = CGWrapper(idEnum, post='\n')
-
- curr.append(idEnum)
-
- traitsDecl = CGGeneric(declare="""
-template <prototypes::ID PrototypeID>
-struct PrototypeTraits;
-
-template <class ConcreteClass>
-struct PrototypeIDMap;
-""")
-
- traitsDecl = CGNamespace.build(['mozilla', 'dom'],
- CGWrapper(traitsDecl, post='\n'))
-
- curr.append(traitsDecl)
-
- # Add include guards.
- curr = CGIncludeGuard('PrototypeList', curr)
-
- # Add the auto-generated comment.
- curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
-
- # Done.
- return curr
-
- @staticmethod
- def RegisterBindings(config):
-
- # TODO - Generate the methods we want
- curr = CGRegisterProtos(config)
-
- # Wrap all of that in our namespaces.
- curr = CGNamespace.build(['mozilla', 'dom'],
- CGWrapper(curr, post='\n'))
- curr = CGWrapper(curr, post='\n')
-
- # Add the includes
- defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface)
- for desc in config.getDescriptors(hasInterfaceObject=True,
- workers=False,
- register=True)]
- defineIncludes.append('nsScriptNameSpaceManager.h')
- curr = CGHeaders([], [], [], defineIncludes, curr)
-
- # Add include guards.
- curr = CGIncludeGuard('RegisterBindings', curr)
-
- # Done.
- return curr
-
- @staticmethod
- def UnionTypes(config):
-
- (includes, declarations, unions) = UnionTypes(config.getDescriptors())
- includes.add("mozilla/dom/BindingUtils.h")
-
- # Wrap all of that in our namespaces.
- curr = CGNamespace.build(['mozilla', 'dom'], unions)
-
- curr = CGWrapper(curr, post='\n')
-
- namespaces = []
- stack = [CGList([])]
- for (clazz, isStruct) in SortedTuples(declarations):
- elements = clazz.split("::")
- clazz = CGClassForwardDeclare(elements.pop(), isStruct=isStruct)
- i = 0
- if len(elements) > 0:
- common = min(len(namespaces), len(elements))
- while i < common and namespaces[i] == elements[i]:
- i += 1
-
- # pop all the namespaces that should be closed
- namespaces = namespaces[:i]
-
- # add all the namespaces that should be opened
- for j, namespace in enumerate(elements[i:]):
- namespaces.append(namespace)
- # every CGNamespace that we add holds a CGList
- list = CGList([])
- # add the new namespace to the list on top of the stack
- stack[i + j].append(CGNamespace(namespace, list))
- # set the top of the namespace stack to the list of the new
- # namespace
- stack[i + j + 1:] = [list]
-
- stack[len(elements)].append(clazz)
-
- curr = CGList([stack[0], curr], "\n")
-
- curr = CGHeaders([], [], includes, [], curr)
-
- # Add include guards.
- curr = CGIncludeGuard('UnionTypes', curr)
-
- # Done.
- return curr
-
- @staticmethod
- def UnionConversions(config):
-
- unions = UnionConversions(config.getDescriptors())
-
- # Wrap all of that in our namespaces.
- curr = CGNamespace.build(['mozilla', 'dom'], unions)
-
- curr = CGWrapper(curr, post='\n')
-
- curr = CGHeaders([], [], ["nsDebug.h", "mozilla/dom/UnionTypes.h", "nsDOMQS.h"], [], curr)
-
- # Add include guards.
- curr = CGIncludeGuard('UnionConversions', curr)
-
- # Done.
- return curr