1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/bindings/Codegen.py Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,13779 @@ 1.4 +# This Source Code Form is subject to the terms of the Mozilla Public 1.5 +# License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 +# You can obtain one at http://mozilla.org/MPL/2.0/. 1.7 + 1.8 +# Common codegen classes. 1.9 + 1.10 +import os 1.11 +import re 1.12 +import string 1.13 +import math 1.14 +import textwrap 1.15 + 1.16 +from WebIDL import BuiltinTypes, IDLBuiltinType, IDLNullValue, IDLSequenceType, IDLType, IDLAttribute, IDLUndefinedValue 1.17 +from Configuration import NoSuchDescriptorError, getTypesFromDescriptor, getTypesFromDictionary, getTypesFromCallback, Descriptor 1.18 + 1.19 +AUTOGENERATED_WARNING_COMMENT = \ 1.20 + "/* THIS FILE IS AUTOGENERATED - DO NOT EDIT */\n\n" 1.21 +ADDPROPERTY_HOOK_NAME = '_addProperty' 1.22 +FINALIZE_HOOK_NAME = '_finalize' 1.23 +CONSTRUCT_HOOK_NAME = '_constructor' 1.24 +LEGACYCALLER_HOOK_NAME = '_legacycaller' 1.25 +HASINSTANCE_HOOK_NAME = '_hasInstance' 1.26 +NEWRESOLVE_HOOK_NAME = '_newResolve' 1.27 +ENUMERATE_HOOK_NAME = '_enumerate' 1.28 +ENUM_ENTRY_VARIABLE_NAME = 'strings' 1.29 +INSTANCE_RESERVED_SLOTS = 3 1.30 + 1.31 + 1.32 +def memberReservedSlot(member): 1.33 + return "(DOM_INSTANCE_RESERVED_SLOTS + %d)" % member.slotIndex 1.34 + 1.35 + 1.36 +def toStringBool(arg): 1.37 + return str(not not arg).lower() 1.38 + 1.39 + 1.40 +def toBindingNamespace(arg): 1.41 + return re.sub("((_workers)?$)", "Binding\\1", arg) 1.42 + 1.43 + 1.44 +def isTypeCopyConstructible(type): 1.45 + # Nullable and sequence stuff doesn't affect copy-constructibility 1.46 + type = type.unroll() 1.47 + return (type.isPrimitive() or type.isString() or type.isEnum() or 1.48 + (type.isUnion() and 1.49 + CGUnionStruct.isUnionCopyConstructible(type)) or 1.50 + (type.isDictionary() and 1.51 + CGDictionary.isDictionaryCopyConstructible(type.inner)) or 1.52 + # Interface types are only copy-constructible if they're Gecko 1.53 + # interfaces. SpiderMonkey interfaces are not copy-constructible 1.54 + # because of rooting issues. 1.55 + (type.isInterface() and type.isGeckoInterface())) 1.56 + 1.57 + 1.58 +def wantsAddProperty(desc): 1.59 + return (desc.concrete and 1.60 + desc.wrapperCache and 1.61 + not (desc.workers and 1.62 + desc.interface.getExtendedAttribute("Global"))) 1.63 + 1.64 + 1.65 +# We'll want to insert the indent at the beginnings of lines, but we 1.66 +# don't want to indent empty lines. So only indent lines that have a 1.67 +# non-newline character on them. 1.68 +lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE) 1.69 + 1.70 + 1.71 +def indent(s, indentLevel=2): 1.72 + """ 1.73 + Indent C++ code. 1.74 + 1.75 + Weird secret feature: this doesn't indent lines that start with # (such as 1.76 + #include lines). 1.77 + """ 1.78 + if s == "": 1.79 + return s 1.80 + return re.sub(lineStartDetector, indentLevel * " ", s) 1.81 + 1.82 + 1.83 +def dedent(s): 1.84 + """ 1.85 + Remove all leading whitespace from s, and remove a blank line 1.86 + at the beginning. 1.87 + """ 1.88 + if s.startswith('\n'): 1.89 + s = s[1:] 1.90 + return textwrap.dedent(s) 1.91 + 1.92 +def fill(template, **args): 1.93 + """ 1.94 + Convenience function for filling in a multiline template. 1.95 + 1.96 + `fill(template, name1=v1, name2=v2)` is a lot like 1.97 + `string.Template(template).substitute({"name1": v1, "name2": v2})`. 1.98 + 1.99 + However, it's shorter, and has a few nice features: 1.100 + 1.101 + * If `template` is indented, fill() automatically dedents it! 1.102 + This makes code using fill() with Python's multiline strings 1.103 + much nicer to look at. 1.104 + 1.105 + * If `template` starts with a blank line, fill() strips it off. 1.106 + (Again, convenient with multiline strings.) 1.107 + 1.108 + * fill() recognizes a special kind of substitution 1.109 + of the form `$*{name}`. 1.110 + 1.111 + Use this to paste in, and automatically indent, multiple lines. 1.112 + (Mnemonic: The `*` is for "multiple lines"). 1.113 + 1.114 + A `$*` substitution must appear by itself on a line, with optional 1.115 + preceding indentation (spaces only). The whole line is replaced by the 1.116 + corresponding keyword argument, indented appropriately. If the 1.117 + argument is an empty string, no output is generated, not even a blank 1.118 + line. 1.119 + """ 1.120 + 1.121 + # This works by transforming the fill()-template to an equivalent 1.122 + # string.Template. 1.123 + multiline_substitution_re = re.compile(r"( *)\$\*{(\w+)}(\n)?") 1.124 + 1.125 + def replace(match): 1.126 + """ 1.127 + Replaces a line like ' $*{xyz}\n' with '${xyz_n}', 1.128 + where n is the indent depth, and add a corresponding entry to args. 1.129 + """ 1.130 + indentation, name, nl = match.groups() 1.131 + depth = len(indentation) 1.132 + 1.133 + # Check that $*{xyz} appears by itself on a line. 1.134 + prev = match.string[:match.start()] 1.135 + if (prev and not prev.endswith("\n")) or nl is None: 1.136 + raise ValueError("Invalid fill() template: $*{%s} must appear by itself on a line" % name) 1.137 + 1.138 + # Multiline text without a newline at the end is probably a mistake. 1.139 + if not (args[name] == "" or args[name].endswith("\n")): 1.140 + raise ValueError("Argument %s with value %r is missing a newline" % (name, args[name])) 1.141 + 1.142 + # Now replace this whole line of template with the indented equivalent. 1.143 + modified_name = name + "_" + str(depth) 1.144 + indented_value = indent(args[name], depth) 1.145 + if modified_name in args: 1.146 + assert args[modified_name] == indented_value 1.147 + else: 1.148 + args[modified_name] = indented_value 1.149 + return "${" + modified_name + "}" 1.150 + 1.151 + t = dedent(template) 1.152 + assert t.endswith("\n") or "\n" not in t 1.153 + t = re.sub(multiline_substitution_re, replace, t) 1.154 + t = string.Template(t) 1.155 + return t.substitute(args) 1.156 + 1.157 + 1.158 +class CGThing(): 1.159 + """ 1.160 + Abstract base class for things that spit out code. 1.161 + """ 1.162 + def __init__(self): 1.163 + pass # Nothing for now 1.164 + 1.165 + def declare(self): 1.166 + """Produce code for a header file.""" 1.167 + assert False # Override me! 1.168 + 1.169 + def define(self): 1.170 + """Produce code for a cpp file.""" 1.171 + assert False # Override me! 1.172 + 1.173 + def deps(self): 1.174 + """Produce the deps for a pp file""" 1.175 + assert False # Override me! 1.176 + 1.177 + 1.178 +class CGStringTable(CGThing): 1.179 + """ 1.180 + Generate a string table for the given strings with a function accessor: 1.181 + 1.182 + const char *accessorName(unsigned int index) { 1.183 + static const char table[] = "..."; 1.184 + static const uint16_t indices = { ... }; 1.185 + return &table[indices[index]]; 1.186 + } 1.187 + 1.188 + This is more efficient than the more natural: 1.189 + 1.190 + const char *table[] = { 1.191 + ... 1.192 + }; 1.193 + 1.194 + The uint16_t indices are smaller than the pointer equivalents, and the 1.195 + string table requires no runtime relocations. 1.196 + """ 1.197 + def __init__(self, accessorName, strings): 1.198 + CGThing.__init__(self) 1.199 + self.accessorName = accessorName 1.200 + self.strings = strings 1.201 + 1.202 + def declare(self): 1.203 + return "extern const char *%s(unsigned int aIndex);\n" % self.accessorName 1.204 + 1.205 + def define(self): 1.206 + table = ' "\\0" '.join('"%s"' % s for s in self.strings) 1.207 + indices = [] 1.208 + currentIndex = 0 1.209 + for s in self.strings: 1.210 + indices.append(currentIndex) 1.211 + currentIndex += len(s) + 1 # for the null terminator 1.212 + return fill( 1.213 + """ 1.214 + const char *${name}(unsigned int aIndex) 1.215 + { 1.216 + static const char table[] = ${table}; 1.217 + static const uint16_t indices[] = { ${indices} }; 1.218 + static_assert(${currentIndex} <= UINT16_MAX, "string table overflow!"); 1.219 + return &table[indices[aIndex]]; 1.220 + } 1.221 + """, 1.222 + name=self.accessorName, 1.223 + table=table, 1.224 + indices=", ".join("%d" % index for index in indices), 1.225 + currentIndex=currentIndex) 1.226 + 1.227 + 1.228 +class CGNativePropertyHooks(CGThing): 1.229 + """ 1.230 + Generate a NativePropertyHooks for a given descriptor 1.231 + """ 1.232 + def __init__(self, descriptor, properties): 1.233 + CGThing.__init__(self) 1.234 + self.descriptor = descriptor 1.235 + self.properties = properties 1.236 + 1.237 + def declare(self): 1.238 + if self.descriptor.workers: 1.239 + return "" 1.240 + return dedent(""" 1.241 + // We declare this as an array so that retrieving a pointer to this 1.242 + // binding's property hooks only requires compile/link-time resolvable 1.243 + // address arithmetic. Declaring it as a pointer instead would require 1.244 + // doing a run-time load to fetch a pointer to this binding's property 1.245 + // hooks. And then structures which embedded a pointer to this structure 1.246 + // would require a run-time load for proper initialization, which would 1.247 + // then induce static constructors. Lots of static constructors. 1.248 + extern const NativePropertyHooks sNativePropertyHooks[]; 1.249 + """).rstrip() # BOGUS strip newline from the last line here (!) 1.250 + 1.251 + def define(self): 1.252 + if self.descriptor.workers: 1.253 + return "" 1.254 + if self.descriptor.concrete and self.descriptor.proxy: 1.255 + resolveOwnProperty = "ResolveOwnProperty" 1.256 + enumerateOwnProperties = "EnumerateOwnProperties" 1.257 + elif self.descriptor.needsXrayResolveHooks(): 1.258 + resolveOwnProperty = "ResolveOwnPropertyViaNewresolve" 1.259 + enumerateOwnProperties = "EnumerateOwnPropertiesViaGetOwnPropertyNames" 1.260 + else: 1.261 + resolveOwnProperty = "nullptr" 1.262 + enumerateOwnProperties = "nullptr" 1.263 + if self.properties.hasNonChromeOnly(): 1.264 + regular = "&sNativeProperties" 1.265 + else: 1.266 + regular = "nullptr" 1.267 + if self.properties.hasChromeOnly(): 1.268 + chrome = "&sChromeOnlyNativeProperties" 1.269 + else: 1.270 + chrome = "nullptr" 1.271 + constructorID = "constructors::id::" 1.272 + if self.descriptor.interface.hasInterfaceObject(): 1.273 + constructorID += self.descriptor.name 1.274 + else: 1.275 + constructorID += "_ID_Count" 1.276 + prototypeID = "prototypes::id::" 1.277 + if self.descriptor.interface.hasInterfacePrototypeObject(): 1.278 + prototypeID += self.descriptor.name 1.279 + else: 1.280 + prototypeID += "_ID_Count" 1.281 + parent = self.descriptor.interface.parent 1.282 + parentHooks = (toBindingNamespace(parent.identifier.name) + "::sNativePropertyHooks" 1.283 + if parent else 'nullptr') 1.284 + 1.285 + return fill( 1.286 + """ 1.287 + const NativePropertyHooks sNativePropertyHooks[] = { { 1.288 + ${resolveOwnProperty}, 1.289 + ${enumerateOwnProperties}, 1.290 + { ${regular}, ${chrome} }, 1.291 + ${prototypeID}, 1.292 + ${constructorID}, 1.293 + ${parentHooks} 1.294 + } }; 1.295 + """, 1.296 + resolveOwnProperty=resolveOwnProperty, 1.297 + enumerateOwnProperties=enumerateOwnProperties, 1.298 + regular=regular, 1.299 + chrome=chrome, 1.300 + prototypeID=prototypeID, 1.301 + constructorID=constructorID, 1.302 + parentHooks=parentHooks) 1.303 + 1.304 + 1.305 +def NativePropertyHooks(descriptor): 1.306 + return "&sWorkerNativePropertyHooks" if descriptor.workers else "sNativePropertyHooks" 1.307 + 1.308 + 1.309 +def DOMClass(descriptor): 1.310 + def make_name(d): 1.311 + return "%s%s" % (d.interface.identifier.name, '_workers' if d.workers else '') 1.312 + 1.313 + protoList = ['prototypes::id::' + make_name(descriptor.getDescriptor(proto)) for proto in descriptor.prototypeChain] 1.314 + # Pad out the list to the right length with _ID_Count so we 1.315 + # guarantee that all the lists are the same length. _ID_Count 1.316 + # is never the ID of any prototype, so it's safe to use as 1.317 + # padding. 1.318 + protoList.extend(['prototypes::id::_ID_Count'] * (descriptor.config.maxProtoChainLength - len(protoList))) 1.319 + 1.320 + return fill( 1.321 + """ 1.322 + { 1.323 + { ${protoChain} }, 1.324 + IsBaseOf<nsISupports, ${nativeType} >::value, 1.325 + ${hooks}, 1.326 + GetParentObject<${nativeType}>::Get, 1.327 + GetProtoObject, 1.328 + GetCCParticipant<${nativeType}>::Get() 1.329 + } 1.330 + """, 1.331 + protoChain=', '.join(protoList), 1.332 + nativeType=descriptor.nativeType, 1.333 + hooks=NativePropertyHooks(descriptor)) 1.334 + 1.335 + 1.336 +class CGDOMJSClass(CGThing): 1.337 + """ 1.338 + Generate a DOMJSClass for a given descriptor 1.339 + """ 1.340 + def __init__(self, descriptor): 1.341 + CGThing.__init__(self) 1.342 + self.descriptor = descriptor 1.343 + 1.344 + def declare(self): 1.345 + return "" 1.346 + 1.347 + def define(self): 1.348 + traceHook = 'nullptr' 1.349 + callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr' 1.350 + slotCount = INSTANCE_RESERVED_SLOTS + self.descriptor.interface.totalMembersInSlots 1.351 + classFlags = "JSCLASS_IS_DOMJSCLASS | " 1.352 + classExtensionAndObjectOps = """\ 1.353 +JS_NULL_CLASS_EXT, 1.354 +JS_NULL_OBJECT_OPS 1.355 +""" 1.356 + if self.descriptor.interface.getExtendedAttribute("Global"): 1.357 + classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS" 1.358 + traceHook = "JS_GlobalObjectTraceHook" 1.359 + if not self.descriptor.workers: 1.360 + classExtensionAndObjectOps = """\ 1.361 +{ 1.362 + nsGlobalWindow::OuterObject, /* outerObject */ 1.363 + nullptr, /* innerObject */ 1.364 + nullptr, /* iteratorObject */ 1.365 + false, /* isWrappedNative */ 1.366 + nullptr /* weakmapKeyDelegateOp */ 1.367 +}, 1.368 +{ 1.369 + nullptr, /* lookupGeneric */ 1.370 + nullptr, /* lookupProperty */ 1.371 + nullptr, /* lookupElement */ 1.372 + nullptr, /* defineGeneric */ 1.373 + nullptr, /* defineProperty */ 1.374 + nullptr, /* defineElement */ 1.375 + nullptr, /* getGeneric */ 1.376 + nullptr, /* getProperty */ 1.377 + nullptr, /* getElement */ 1.378 + nullptr, /* setGeneric */ 1.379 + nullptr, /* setProperty */ 1.380 + nullptr, /* setElement */ 1.381 + nullptr, /* getGenericAttributes */ 1.382 + nullptr, /* setGenericAttributes */ 1.383 + nullptr, /* deleteProperty */ 1.384 + nullptr, /* deleteElement */ 1.385 + nullptr, /* watch */ 1.386 + nullptr, /* unwatch */ 1.387 + nullptr, /* slice */ 1.388 + nullptr, /* enumerate */ 1.389 + JS_ObjectToOuterObject /* thisObject */ 1.390 +} 1.391 +""" 1.392 + else: 1.393 + classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount 1.394 + if self.descriptor.interface.getExtendedAttribute("NeedNewResolve"): 1.395 + newResolveHook = "(JSResolveOp)" + NEWRESOLVE_HOOK_NAME 1.396 + classFlags += " | JSCLASS_NEW_RESOLVE" 1.397 + enumerateHook = ENUMERATE_HOOK_NAME 1.398 + elif self.descriptor.interface.getExtendedAttribute("Global"): 1.399 + newResolveHook = "(JSResolveOp) mozilla::dom::ResolveGlobal" 1.400 + classFlags += " | JSCLASS_NEW_RESOLVE" 1.401 + enumerateHook = "mozilla::dom::EnumerateGlobal" 1.402 + else: 1.403 + newResolveHook = "JS_ResolveStub" 1.404 + enumerateHook = "JS_EnumerateStub" 1.405 + 1.406 + return fill( # BOGUS extra blank line at the top 1.407 + """ 1.408 + 1.409 + static const DOMJSClass Class = { 1.410 + { "${name}", 1.411 + ${flags}, 1.412 + ${addProperty}, /* addProperty */ 1.413 + JS_DeletePropertyStub, /* delProperty */ 1.414 + JS_PropertyStub, /* getProperty */ 1.415 + JS_StrictPropertyStub, /* setProperty */ 1.416 + ${enumerate}, /* enumerate */ 1.417 + ${resolve}, /* resolve */ 1.418 + JS_ConvertStub, 1.419 + ${finalize}, /* finalize */ 1.420 + ${call}, /* call */ 1.421 + nullptr, /* hasInstance */ 1.422 + nullptr, /* construct */ 1.423 + ${trace}, /* trace */ 1.424 + JS_NULL_CLASS_SPEC, 1.425 + $*{classExtensionAndObjectOps} 1.426 + }, 1.427 + $*{descriptor} 1.428 + }; 1.429 + """, 1.430 + name=self.descriptor.interface.identifier.name, 1.431 + flags=classFlags, 1.432 + addProperty=ADDPROPERTY_HOOK_NAME if wantsAddProperty(self.descriptor) else 'JS_PropertyStub', 1.433 + enumerate=enumerateHook, 1.434 + resolve=newResolveHook, 1.435 + finalize=FINALIZE_HOOK_NAME, 1.436 + call=callHook, 1.437 + trace=traceHook, 1.438 + classExtensionAndObjectOps=classExtensionAndObjectOps, 1.439 + descriptor=DOMClass(self.descriptor)) 1.440 + 1.441 + 1.442 +class CGDOMProxyJSClass(CGThing): 1.443 + """ 1.444 + Generate a DOMJSClass for a given proxy descriptor 1.445 + """ 1.446 + def __init__(self, descriptor): 1.447 + CGThing.__init__(self) 1.448 + self.descriptor = descriptor 1.449 + 1.450 + def declare(self): 1.451 + return "" 1.452 + 1.453 + def define(self): 1.454 + flags = ["JSCLASS_IS_DOMJSCLASS"] 1.455 + # We don't use an IDL annotation for JSCLASS_EMULATES_UNDEFINED because 1.456 + # we don't want people ever adding that to any interface other than 1.457 + # HTMLAllCollection. So just hardcode it here. 1.458 + if self.descriptor.interface.identifier.name == "HTMLAllCollection": 1.459 + flags.append("JSCLASS_EMULATES_UNDEFINED") 1.460 + callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr' 1.461 + return fill( # BOGUS extra blank line at the top 1.462 + """ 1.463 + 1.464 + static const DOMJSClass Class = { 1.465 + PROXY_CLASS_DEF("${name}", 1.466 + 0, /* extra slots */ 1.467 + ${flags}, 1.468 + ${call}, /* call */ 1.469 + nullptr /* construct */), 1.470 + $*{descriptor} 1.471 + }; 1.472 + """, 1.473 + name=self.descriptor.interface.identifier.name, 1.474 + flags=" | ".join(flags), 1.475 + call=callHook, 1.476 + descriptor=DOMClass(self.descriptor)) 1.477 + 1.478 + 1.479 +def PrototypeIDAndDepth(descriptor): 1.480 + prototypeID = "prototypes::id::" 1.481 + if descriptor.interface.hasInterfacePrototypeObject(): 1.482 + prototypeID += descriptor.interface.identifier.name 1.483 + if descriptor.workers: 1.484 + prototypeID += "_workers" 1.485 + depth = "PrototypeTraits<%s>::Depth" % prototypeID 1.486 + else: 1.487 + prototypeID += "_ID_Count" 1.488 + depth = "0" 1.489 + return (prototypeID, depth) 1.490 + 1.491 + 1.492 +def UseHolderForUnforgeable(descriptor): 1.493 + return (descriptor.concrete and 1.494 + descriptor.proxy and 1.495 + any(m for m in descriptor.interface.members if m.isAttr() and m.isUnforgeable())) 1.496 + 1.497 + 1.498 +def CallOnUnforgeableHolder(descriptor, code, isXrayCheck=None, 1.499 + useSharedRoot=False): 1.500 + """ 1.501 + Generate the code to execute the code in "code" on an unforgeable holder if 1.502 + needed. code should be a string containing the code to execute. If it 1.503 + contains a ${holder} string parameter it will be replaced with the 1.504 + unforgeable holder object. 1.505 + 1.506 + If isXrayCheck is not None it should be a string that contains a statement 1.507 + returning whether proxy is an Xray. If isXrayCheck is None the generated 1.508 + code won't try to unwrap Xrays. 1.509 + 1.510 + If useSharedRoot is true, we will use an existing 1.511 + JS::Rooted<JSObject*> sharedRoot for storing our unforgeable holder instead 1.512 + of declaring a new Rooted. 1.513 + """ 1.514 + if isXrayCheck is not None: 1.515 + pre = fill( 1.516 + """ 1.517 + // Scope for 'global', 'ac' and 'unforgeableHolder' 1.518 + { 1.519 + JS::Rooted<JSObject*> global(cx); 1.520 + Maybe<JSAutoCompartment> ac; 1.521 + if (${isXrayCheck}) { 1.522 + global = js::GetGlobalForObjectCrossCompartment(js::UncheckedUnwrap(proxy)); 1.523 + ac.construct(cx, global); 1.524 + } else { 1.525 + global = js::GetGlobalForObjectCrossCompartment(proxy); 1.526 + } 1.527 + """, 1.528 + isXrayCheck=isXrayCheck) 1.529 + else: 1.530 + pre = dedent(""" 1.531 + // Scope for 'global' and 'unforgeableHolder' 1.532 + { 1.533 + JSObject* global = js::GetGlobalForObjectCrossCompartment(proxy); 1.534 + """) 1.535 + 1.536 + if useSharedRoot: 1.537 + holderDecl = "JS::Rooted<JSObject*>& unforgeableHolder(sharedRoot);\n" 1.538 + else: 1.539 + holderDecl = "JS::Rooted<JSObject*> unforgeableHolder(cx);\n" 1.540 + 1.541 + code = string.Template(code).substitute({"holder": "unforgeableHolder"}) 1.542 + return fill( 1.543 + """ 1.544 + $*{pre} 1.545 + $*{holderDecl} 1.546 + unforgeableHolder = GetUnforgeableHolder(global, prototypes::id::${name}); 1.547 + $*{code} 1.548 + } 1.549 + """, 1.550 + pre=pre, 1.551 + holderDecl=holderDecl, 1.552 + name=descriptor.name, 1.553 + code=code) 1.554 + 1.555 + 1.556 +class CGPrototypeJSClass(CGThing): 1.557 + def __init__(self, descriptor, properties): 1.558 + CGThing.__init__(self) 1.559 + self.descriptor = descriptor 1.560 + self.properties = properties 1.561 + 1.562 + def declare(self): 1.563 + # We're purely for internal consumption 1.564 + return "" 1.565 + 1.566 + def define(self): 1.567 + prototypeID, depth = PrototypeIDAndDepth(self.descriptor) 1.568 + slotCount = "DOM_INTERFACE_PROTO_SLOTS_BASE" 1.569 + if UseHolderForUnforgeable(self.descriptor): 1.570 + slotCount += " + 1 /* slot for the JSObject holding the unforgeable properties */" 1.571 + return fill( 1.572 + """ 1.573 + static const DOMIfaceAndProtoJSClass PrototypeClass = { 1.574 + { 1.575 + "${name}Prototype", 1.576 + JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}), 1.577 + JS_PropertyStub, /* addProperty */ 1.578 + JS_DeletePropertyStub, /* delProperty */ 1.579 + JS_PropertyStub, /* getProperty */ 1.580 + JS_StrictPropertyStub, /* setProperty */ 1.581 + JS_EnumerateStub, 1.582 + JS_ResolveStub, 1.583 + JS_ConvertStub, 1.584 + nullptr, /* finalize */ 1.585 + nullptr, /* call */ 1.586 + nullptr, /* hasInstance */ 1.587 + nullptr, /* construct */ 1.588 + nullptr, /* trace */ 1.589 + JSCLASS_NO_INTERNAL_MEMBERS 1.590 + }, 1.591 + eInterfacePrototype, 1.592 + ${hooks}, 1.593 + "[object ${name}Prototype]", 1.594 + ${prototypeID}, 1.595 + ${depth} 1.596 + }; 1.597 + """, 1.598 + name=self.descriptor.interface.identifier.name, 1.599 + slotCount=slotCount, 1.600 + hooks=NativePropertyHooks(self.descriptor), 1.601 + prototypeID=prototypeID, 1.602 + depth=depth) 1.603 + 1.604 + 1.605 +def NeedsGeneratedHasInstance(descriptor): 1.606 + return descriptor.hasXPConnectImpls or descriptor.interface.isConsequential() 1.607 + 1.608 + 1.609 +class CGInterfaceObjectJSClass(CGThing): 1.610 + def __init__(self, descriptor, properties): 1.611 + CGThing.__init__(self) 1.612 + self.descriptor = descriptor 1.613 + self.properties = properties 1.614 + 1.615 + def declare(self): 1.616 + # We're purely for internal consumption 1.617 + return "" 1.618 + 1.619 + def define(self): 1.620 + if self.descriptor.interface.ctor(): 1.621 + ctorname = CONSTRUCT_HOOK_NAME 1.622 + else: 1.623 + ctorname = "ThrowingConstructor" 1.624 + if NeedsGeneratedHasInstance(self.descriptor): 1.625 + hasinstance = HASINSTANCE_HOOK_NAME 1.626 + elif self.descriptor.interface.hasInterfacePrototypeObject(): 1.627 + hasinstance = "InterfaceHasInstance" 1.628 + else: 1.629 + hasinstance = "nullptr" 1.630 + prototypeID, depth = PrototypeIDAndDepth(self.descriptor) 1.631 + slotCount = "DOM_INTERFACE_SLOTS_BASE" 1.632 + if len(self.descriptor.interface.namedConstructors) > 0: 1.633 + slotCount += (" + %i /* slots for the named constructors */" % 1.634 + len(self.descriptor.interface.namedConstructors)) 1.635 + return fill( # BOGUS extra newline at the top 1.636 + """ 1.637 + 1.638 + static const DOMIfaceAndProtoJSClass InterfaceObjectClass = { 1.639 + { 1.640 + "Function", 1.641 + JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}), 1.642 + JS_PropertyStub, /* addProperty */ 1.643 + JS_DeletePropertyStub, /* delProperty */ 1.644 + JS_PropertyStub, /* getProperty */ 1.645 + JS_StrictPropertyStub, /* setProperty */ 1.646 + JS_EnumerateStub, 1.647 + JS_ResolveStub, 1.648 + JS_ConvertStub, 1.649 + nullptr, /* finalize */ 1.650 + ${ctorname}, /* call */ 1.651 + ${hasInstance}, /* hasInstance */ 1.652 + ${ctorname}, /* construct */ 1.653 + nullptr, /* trace */ 1.654 + JSCLASS_NO_INTERNAL_MEMBERS 1.655 + }, 1.656 + eInterface, 1.657 + ${hooks}, 1.658 + "function ${name}() {\\n [native code]\\n}", 1.659 + ${prototypeID}, 1.660 + ${depth} 1.661 + }; 1.662 + """, 1.663 + slotCount=slotCount, 1.664 + ctorname=ctorname, 1.665 + hasInstance=hasinstance, 1.666 + hooks=NativePropertyHooks(self.descriptor), 1.667 + name=self.descriptor.interface.identifier.name, 1.668 + prototypeID=prototypeID, 1.669 + depth=depth) 1.670 + 1.671 + 1.672 +class CGList(CGThing): 1.673 + """ 1.674 + Generate code for a list of GCThings. Just concatenates them together, with 1.675 + an optional joiner string. "\n" is a common joiner. 1.676 + """ 1.677 + def __init__(self, children, joiner=""): 1.678 + CGThing.__init__(self) 1.679 + # Make a copy of the kids into a list, because if someone passes in a 1.680 + # generator we won't be able to both declare and define ourselves, or 1.681 + # define ourselves more than once! 1.682 + self.children = list(children) 1.683 + self.joiner = joiner 1.684 + 1.685 + def append(self, child): 1.686 + self.children.append(child) 1.687 + 1.688 + def prepend(self, child): 1.689 + self.children.insert(0, child) 1.690 + 1.691 + def extend(self, kids): 1.692 + self.children.extend(kids) 1.693 + 1.694 + def join(self, iterable): 1.695 + return self.joiner.join(s for s in iterable if len(s) > 0) 1.696 + 1.697 + def declare(self): 1.698 + return self.join(child.declare() for child in self.children if child is not None) 1.699 + 1.700 + def define(self): 1.701 + return self.join(child.define() for child in self.children if child is not None) 1.702 + 1.703 + def deps(self): 1.704 + deps = set() 1.705 + for child in self.children: 1.706 + if child is None: 1.707 + continue 1.708 + deps = deps.union(child.deps()) 1.709 + return deps 1.710 + 1.711 + 1.712 +class CGGeneric(CGThing): 1.713 + """ 1.714 + A class that spits out a fixed string into the codegen. Can spit out a 1.715 + separate string for the declaration too. 1.716 + """ 1.717 + def __init__(self, define="", declare=""): 1.718 + self.declareText = declare 1.719 + self.defineText = define 1.720 + 1.721 + def declare(self): 1.722 + return self.declareText 1.723 + 1.724 + def define(self): 1.725 + return self.defineText 1.726 + 1.727 + def deps(self): 1.728 + return set() 1.729 + 1.730 + 1.731 +class CGIndenter(CGThing): 1.732 + """ 1.733 + A class that takes another CGThing and generates code that indents that 1.734 + CGThing by some number of spaces. The default indent is two spaces. 1.735 + """ 1.736 + def __init__(self, child, indentLevel=2, declareOnly=False): 1.737 + assert isinstance(child, CGThing) 1.738 + CGThing.__init__(self) 1.739 + self.child = child 1.740 + self.indentLevel = indentLevel 1.741 + self.declareOnly = declareOnly 1.742 + 1.743 + def declare(self): 1.744 + return indent(self.child.declare(), self.indentLevel) 1.745 + 1.746 + def define(self): 1.747 + defn = self.child.define() 1.748 + if self.declareOnly: 1.749 + return defn 1.750 + else: 1.751 + return indent(defn, self.indentLevel) 1.752 + 1.753 + 1.754 +class CGWrapper(CGThing): 1.755 + """ 1.756 + Generic CGThing that wraps other CGThings with pre and post text. 1.757 + """ 1.758 + def __init__(self, child, pre="", post="", declarePre=None, 1.759 + declarePost=None, definePre=None, definePost=None, 1.760 + declareOnly=False, defineOnly=False, reindent=False): 1.761 + CGThing.__init__(self) 1.762 + self.child = child 1.763 + self.declarePre = declarePre or pre 1.764 + self.declarePost = declarePost or post 1.765 + self.definePre = definePre or pre 1.766 + self.definePost = definePost or post 1.767 + self.declareOnly = declareOnly 1.768 + self.defineOnly = defineOnly 1.769 + self.reindent = reindent 1.770 + 1.771 + def declare(self): 1.772 + if self.defineOnly: 1.773 + return '' 1.774 + decl = self.child.declare() 1.775 + if self.reindent: 1.776 + decl = self.reindentString(decl, self.declarePre) 1.777 + return self.declarePre + decl + self.declarePost 1.778 + 1.779 + def define(self): 1.780 + if self.declareOnly: 1.781 + return '' 1.782 + defn = self.child.define() 1.783 + if self.reindent: 1.784 + defn = self.reindentString(defn, self.definePre) 1.785 + return self.definePre + defn + self.definePost 1.786 + 1.787 + @staticmethod 1.788 + def reindentString(stringToIndent, widthString): 1.789 + # We don't use lineStartDetector because we don't want to 1.790 + # insert whitespace at the beginning of our _first_ line. 1.791 + # Use the length of the last line of width string, in case 1.792 + # it is a multiline string. 1.793 + lastLineWidth = len(widthString.splitlines()[-1]) 1.794 + return stripTrailingWhitespace( 1.795 + stringToIndent.replace("\n", "\n" + (" " * lastLineWidth))) 1.796 + 1.797 + def deps(self): 1.798 + return self.child.deps() 1.799 + 1.800 + 1.801 +class CGIfWrapper(CGList): 1.802 + def __init__(self, child, condition): 1.803 + CGList.__init__(self, [ 1.804 + CGWrapper(CGGeneric(condition), pre="if (", post=") {\n", reindent=True), 1.805 + CGIndenter(child), 1.806 + CGGeneric("}\n") 1.807 + ]) 1.808 + 1.809 + 1.810 +class CGIfElseWrapper(CGList): 1.811 + def __init__(self, condition, ifTrue, ifFalse): 1.812 + CGList.__init__(self, [ 1.813 + CGWrapper(CGGeneric(condition), pre="if (", post=") {\n", reindent=True), 1.814 + CGIndenter(ifTrue), 1.815 + CGGeneric("} else {\n"), 1.816 + CGIndenter(ifFalse), 1.817 + CGGeneric("}\n") 1.818 + ]) 1.819 + 1.820 + 1.821 +class CGElseChain(CGThing): 1.822 + """ 1.823 + Concatenate if statements in an if-else-if-else chain. 1.824 + """ 1.825 + def __init__(self, children): 1.826 + self.children = [c for c in children if c is not None] 1.827 + 1.828 + def declare(self): 1.829 + assert False 1.830 + 1.831 + def define(self): 1.832 + if not self.children: 1.833 + return "" 1.834 + s = self.children[0].define() 1.835 + assert s.endswith("\n") 1.836 + for child in self.children[1:]: 1.837 + code = child.define() 1.838 + assert code.startswith("if") or code.startswith("{") 1.839 + assert code.endswith("\n") 1.840 + s = s.rstrip() + " else " + code 1.841 + return s 1.842 + 1.843 + 1.844 +class CGTemplatedType(CGWrapper): 1.845 + def __init__(self, templateName, child, isConst=False, isReference=False): 1.846 + const = "const " if isConst else "" 1.847 + pre = "%s%s<" % (const, templateName) 1.848 + ref = "&" if isReference else "" 1.849 + post = ">%s" % ref 1.850 + CGWrapper.__init__(self, child, pre=pre, post=post) 1.851 + 1.852 + 1.853 +class CGNamespace(CGWrapper): 1.854 + def __init__(self, namespace, child, declareOnly=False): 1.855 + pre = "namespace %s {\n" % namespace 1.856 + post = "} // namespace %s\n" % namespace 1.857 + CGWrapper.__init__(self, child, pre=pre, post=post, 1.858 + declareOnly=declareOnly) 1.859 + 1.860 + @staticmethod 1.861 + def build(namespaces, child, declareOnly=False): 1.862 + """ 1.863 + Static helper method to build multiple wrapped namespaces. 1.864 + """ 1.865 + if not namespaces: 1.866 + return CGWrapper(child, declareOnly=declareOnly) 1.867 + inner = CGNamespace.build(namespaces[1:], child, declareOnly=declareOnly) 1.868 + return CGNamespace(namespaces[0], inner, declareOnly=declareOnly) 1.869 + 1.870 + 1.871 +class CGIncludeGuard(CGWrapper): 1.872 + """ 1.873 + Generates include guards for a header. 1.874 + """ 1.875 + def __init__(self, prefix, child): 1.876 + """|prefix| is the filename without the extension.""" 1.877 + define = 'mozilla_dom_%s_h' % prefix 1.878 + CGWrapper.__init__(self, child, 1.879 + declarePre='#ifndef %s\n#define %s\n\n' % (define, define), 1.880 + declarePost='\n#endif // %s\n' % define) 1.881 + 1.882 + 1.883 +def getRelevantProviders(descriptor, config): 1.884 + if descriptor is not None: 1.885 + return [descriptor] 1.886 + # Do both the non-worker and worker versions 1.887 + return [ 1.888 + config.getDescriptorProvider(False), 1.889 + config.getDescriptorProvider(True) 1.890 + ] 1.891 + 1.892 + 1.893 +def getAllTypes(descriptors, dictionaries, callbacks): 1.894 + """ 1.895 + Generate all the types we're dealing with. For each type, a tuple 1.896 + containing type, descriptor, dictionary is yielded. The 1.897 + descriptor and dictionary can be None if the type does not come 1.898 + from a descriptor or dictionary; they will never both be non-None. 1.899 + """ 1.900 + for d in descriptors: 1.901 + if d.interface.isExternal(): 1.902 + continue 1.903 + for t in getTypesFromDescriptor(d): 1.904 + yield (t, d, None) 1.905 + for dictionary in dictionaries: 1.906 + for t in getTypesFromDictionary(dictionary): 1.907 + yield (t, None, dictionary) 1.908 + for callback in callbacks: 1.909 + for t in getTypesFromCallback(callback): 1.910 + yield (t, None, None) 1.911 + 1.912 + 1.913 +class CGHeaders(CGWrapper): 1.914 + """ 1.915 + Generates the appropriate include statements. 1.916 + """ 1.917 + def __init__(self, descriptors, dictionaries, callbacks, 1.918 + callbackDescriptors, 1.919 + declareIncludes, defineIncludes, prefix, child, 1.920 + config=None, jsImplementedDescriptors=[]): 1.921 + """ 1.922 + Builds a set of includes to cover |descriptors|. 1.923 + 1.924 + Also includes the files in |declareIncludes| in the header 1.925 + file and the files in |defineIncludes| in the .cpp. 1.926 + 1.927 + |prefix| contains the basename of the file that we generate include 1.928 + statements for. 1.929 + """ 1.930 + 1.931 + # Determine the filenames for which we need headers. 1.932 + interfaceDeps = [d.interface for d in descriptors] 1.933 + ancestors = [] 1.934 + for iface in interfaceDeps: 1.935 + if iface.parent: 1.936 + # We're going to need our parent's prototype, to use as the 1.937 + # prototype of our prototype object. 1.938 + ancestors.append(iface.parent) 1.939 + # And if we have an interface object, we'll need the nearest 1.940 + # ancestor with an interface object too, so we can use its 1.941 + # interface object as the proto of our interface object. 1.942 + if iface.hasInterfaceObject(): 1.943 + parent = iface.parent 1.944 + while parent and not parent.hasInterfaceObject(): 1.945 + parent = parent.parent 1.946 + if parent: 1.947 + ancestors.append(parent) 1.948 + interfaceDeps.extend(ancestors) 1.949 + bindingIncludes = set(self.getDeclarationFilename(d) for d in interfaceDeps) 1.950 + 1.951 + # Grab all the implementation declaration files we need. 1.952 + implementationIncludes = set(d.headerFile for d in descriptors if d.needsHeaderInclude()) 1.953 + 1.954 + # Grab the includes for checking hasInstance 1.955 + interfacesImplementingSelf = set() 1.956 + for d in descriptors: 1.957 + interfacesImplementingSelf |= d.interface.interfacesImplementingSelf 1.958 + implementationIncludes |= set(self.getDeclarationFilename(i) for i in 1.959 + interfacesImplementingSelf) 1.960 + 1.961 + # Grab the includes for the things that involve XPCOM interfaces 1.962 + hasInstanceIncludes = set("nsIDOM" + d.interface.identifier.name + ".h" for d 1.963 + in descriptors if 1.964 + NeedsGeneratedHasInstance(d) and 1.965 + d.interface.hasInterfacePrototypeObject()) 1.966 + 1.967 + # Now find all the things we'll need as arguments because we 1.968 + # need to wrap or unwrap them. 1.969 + bindingHeaders = set() 1.970 + declareIncludes = set(declareIncludes) 1.971 + 1.972 + def addHeadersForType((t, descriptor, dictionary)): 1.973 + """ 1.974 + Add the relevant headers for this type. We use descriptor and 1.975 + dictionary, if passed, to decide what to do with interface types. 1.976 + """ 1.977 + assert not descriptor or not dictionary 1.978 + # Dictionaries have members that need to be actually 1.979 + # declared, not just forward-declared. 1.980 + if dictionary: 1.981 + headerSet = declareIncludes 1.982 + else: 1.983 + headerSet = bindingHeaders 1.984 + if t.nullable(): 1.985 + # Need to make sure that Nullable as a dictionary 1.986 + # member works. 1.987 + headerSet.add("mozilla/dom/Nullable.h") 1.988 + unrolled = t.unroll() 1.989 + if unrolled.isUnion(): 1.990 + # UnionConversions.h includes UnionTypes.h 1.991 + bindingHeaders.add("mozilla/dom/UnionConversions.h") 1.992 + if dictionary: 1.993 + # Our dictionary definition is in the header and 1.994 + # needs the union type. 1.995 + declareIncludes.add("mozilla/dom/UnionTypes.h") 1.996 + elif unrolled.isDate(): 1.997 + if dictionary or jsImplementedDescriptors: 1.998 + declareIncludes.add("mozilla/dom/Date.h") 1.999 + else: 1.1000 + bindingHeaders.add("mozilla/dom/Date.h") 1.1001 + elif unrolled.isInterface(): 1.1002 + if unrolled.isSpiderMonkeyInterface(): 1.1003 + bindingHeaders.add("jsfriendapi.h") 1.1004 + headerSet.add("mozilla/dom/TypedArray.h") 1.1005 + else: 1.1006 + providers = getRelevantProviders(descriptor, config) 1.1007 + for p in providers: 1.1008 + try: 1.1009 + typeDesc = p.getDescriptor(unrolled.inner.identifier.name) 1.1010 + except NoSuchDescriptorError: 1.1011 + continue 1.1012 + # Dictionaries with interface members rely on the 1.1013 + # actual class definition of that interface member 1.1014 + # being visible in the binding header, because they 1.1015 + # store them in nsRefPtr and have inline 1.1016 + # constructors/destructors. 1.1017 + # 1.1018 + # XXXbz maybe dictionaries with interface members 1.1019 + # should just have out-of-line constructors and 1.1020 + # destructors? 1.1021 + headerSet.add(typeDesc.headerFile) 1.1022 + elif unrolled.isDictionary(): 1.1023 + headerSet.add(self.getDeclarationFilename(unrolled.inner)) 1.1024 + elif unrolled.isCallback(): 1.1025 + # Callbacks are both a type and an object 1.1026 + headerSet.add(self.getDeclarationFilename(unrolled)) 1.1027 + elif unrolled.isFloat() and not unrolled.isUnrestricted(): 1.1028 + # Restricted floats are tested for finiteness 1.1029 + bindingHeaders.add("mozilla/FloatingPoint.h") 1.1030 + bindingHeaders.add("mozilla/dom/PrimitiveConversions.h") 1.1031 + elif unrolled.isEnum(): 1.1032 + filename = self.getDeclarationFilename(unrolled.inner) 1.1033 + declareIncludes.add(filename) 1.1034 + elif unrolled.isPrimitive(): 1.1035 + bindingHeaders.add("mozilla/dom/PrimitiveConversions.h") 1.1036 + elif unrolled.isMozMap(): 1.1037 + if dictionary or jsImplementedDescriptors: 1.1038 + declareIncludes.add("mozilla/dom/MozMap.h") 1.1039 + else: 1.1040 + bindingHeaders.add("mozilla/dom/MozMap.h") 1.1041 + # Also add headers for the type the MozMap is 1.1042 + # parametrized over, if needed. 1.1043 + addHeadersForType((t.inner, descriptor, dictionary)) 1.1044 + 1.1045 + map(addHeadersForType, 1.1046 + getAllTypes(descriptors + callbackDescriptors, dictionaries, 1.1047 + callbacks)) 1.1048 + 1.1049 + # Now make sure we're not trying to include the header from inside itself 1.1050 + declareIncludes.discard(prefix + ".h") 1.1051 + 1.1052 + # Now for non-callback descriptors make sure we include any 1.1053 + # headers needed by Func declarations. 1.1054 + for desc in descriptors: 1.1055 + if desc.interface.isExternal(): 1.1056 + continue 1.1057 + 1.1058 + def addHeaderForFunc(func): 1.1059 + if func is None: 1.1060 + return 1.1061 + # Include the right class header, which we can only do 1.1062 + # if this is a class member function. 1.1063 + if not desc.headerIsDefault: 1.1064 + # An explicit header file was provided, assume that we know 1.1065 + # what we're doing. 1.1066 + return 1.1067 + 1.1068 + if "::" in func: 1.1069 + # Strip out the function name and convert "::" to "/" 1.1070 + bindingHeaders.add("/".join(func.split("::")[:-1]) + ".h") 1.1071 + 1.1072 + for m in desc.interface.members: 1.1073 + addHeaderForFunc(PropertyDefiner.getStringAttr(m, "Func")) 1.1074 + # getExtendedAttribute() returns a list, extract the entry. 1.1075 + funcList = desc.interface.getExtendedAttribute("Func") 1.1076 + if funcList is not None: 1.1077 + addHeaderForFunc(funcList[0]) 1.1078 + 1.1079 + for d in dictionaries: 1.1080 + if d.parent: 1.1081 + declareIncludes.add(self.getDeclarationFilename(d.parent)) 1.1082 + bindingHeaders.add(self.getDeclarationFilename(d)) 1.1083 + 1.1084 + for c in callbacks: 1.1085 + bindingHeaders.add(self.getDeclarationFilename(c)) 1.1086 + 1.1087 + for c in callbackDescriptors: 1.1088 + bindingHeaders.add(self.getDeclarationFilename(c.interface)) 1.1089 + 1.1090 + if len(callbacks) != 0: 1.1091 + # We need CallbackFunction to serve as our parent class 1.1092 + declareIncludes.add("mozilla/dom/CallbackFunction.h") 1.1093 + # And we need BindingUtils.h so we can wrap "this" objects 1.1094 + declareIncludes.add("mozilla/dom/BindingUtils.h") 1.1095 + 1.1096 + if len(callbackDescriptors) != 0 or len(jsImplementedDescriptors) != 0: 1.1097 + # We need CallbackInterface to serve as our parent class 1.1098 + declareIncludes.add("mozilla/dom/CallbackInterface.h") 1.1099 + # And we need BindingUtils.h so we can wrap "this" objects 1.1100 + declareIncludes.add("mozilla/dom/BindingUtils.h") 1.1101 + 1.1102 + # Also need to include the headers for ancestors of 1.1103 + # JS-implemented interfaces. 1.1104 + for jsImplemented in jsImplementedDescriptors: 1.1105 + jsParent = jsImplemented.interface.parent 1.1106 + if jsParent: 1.1107 + parentDesc = jsImplemented.getDescriptor(jsParent.identifier.name) 1.1108 + declareIncludes.add(parentDesc.jsImplParentHeader) 1.1109 + 1.1110 + # Let the machinery do its thing. 1.1111 + def _includeString(includes): 1.1112 + return ''.join(['#include "%s"\n' % i for i in includes]) + '\n' 1.1113 + CGWrapper.__init__(self, child, 1.1114 + declarePre=_includeString(sorted(declareIncludes)), 1.1115 + definePre=_includeString(sorted(set(defineIncludes) | 1.1116 + bindingIncludes | 1.1117 + bindingHeaders | 1.1118 + hasInstanceIncludes | 1.1119 + implementationIncludes))) 1.1120 + 1.1121 + @staticmethod 1.1122 + def getDeclarationFilename(decl): 1.1123 + # Use our local version of the header, not the exported one, so that 1.1124 + # test bindings, which don't export, will work correctly. 1.1125 + basename = os.path.basename(decl.filename()) 1.1126 + return basename.replace('.webidl', 'Binding.h') 1.1127 + 1.1128 + 1.1129 +def SortedDictValues(d): 1.1130 + """ 1.1131 + Returns a list of values from the dict sorted by key. 1.1132 + """ 1.1133 + return [v for k, v in sorted(d.items())] 1.1134 + 1.1135 + 1.1136 +def UnionTypes(descriptors, dictionaries, callbacks, config): 1.1137 + """ 1.1138 + Returns a tuple containing a set of header filenames to include in 1.1139 + UnionTypes.h, a set of header filenames to include in UnionTypes.cpp, a set 1.1140 + of tuples containing a type declaration and a boolean if the type is a 1.1141 + struct for member types of the unions and a CGList containing CGUnionStructs 1.1142 + for every union. 1.1143 + """ 1.1144 + 1.1145 + # Now find all the things we'll need as arguments and return values because 1.1146 + # we need to wrap or unwrap them. 1.1147 + headers = set() 1.1148 + implheaders = set(["UnionTypes.h"]) 1.1149 + declarations = set() 1.1150 + unionStructs = dict() 1.1151 + owningUnionStructs = dict() 1.1152 + 1.1153 + for t, descriptor, dictionary in getAllTypes(descriptors, dictionaries, callbacks): 1.1154 + # Add info for the given type. descriptor and dictionary, if present, are 1.1155 + # used to figure out what to do with interface types. 1.1156 + assert not descriptor or not dictionary 1.1157 + 1.1158 + t = t.unroll() 1.1159 + while t.isMozMap(): 1.1160 + t = t.inner.unroll() 1.1161 + if not t.isUnion(): 1.1162 + continue 1.1163 + name = str(t) 1.1164 + if name not in unionStructs: 1.1165 + providers = getRelevantProviders(descriptor, config) 1.1166 + # FIXME: Unions are broken in workers. See bug 809899. 1.1167 + unionStructs[name] = CGUnionStruct(t, providers[0]) 1.1168 + owningUnionStructs[name] = CGUnionStruct(t, providers[0], 1.1169 + ownsMembers=True) 1.1170 + 1.1171 + def addHeadersForType(f): 1.1172 + if f.nullable(): 1.1173 + headers.add("mozilla/dom/Nullable.h") 1.1174 + f = f.unroll() 1.1175 + if f.isInterface(): 1.1176 + if f.isSpiderMonkeyInterface(): 1.1177 + headers.add("jsfriendapi.h") 1.1178 + headers.add("mozilla/dom/TypedArray.h") 1.1179 + else: 1.1180 + for p in providers: 1.1181 + try: 1.1182 + typeDesc = p.getDescriptor(f.inner.identifier.name) 1.1183 + except NoSuchDescriptorError: 1.1184 + continue 1.1185 + if typeDesc.interface.isCallback(): 1.1186 + # Callback interfaces always use strong refs, so 1.1187 + # we need to include the right header to be able 1.1188 + # to Release() in our inlined code. 1.1189 + headers.add(typeDesc.headerFile) 1.1190 + else: 1.1191 + declarations.add((typeDesc.nativeType, False)) 1.1192 + implheaders.add(typeDesc.headerFile) 1.1193 + elif f.isDictionary(): 1.1194 + # For a dictionary, we need to see its declaration in 1.1195 + # UnionTypes.h so we have its sizeof and know how big to 1.1196 + # make our union. 1.1197 + headers.add(CGHeaders.getDeclarationFilename(f.inner)) 1.1198 + # And if it needs rooting, we need RootedDictionary too 1.1199 + if typeNeedsRooting(f): 1.1200 + headers.add("mozilla/dom/RootedDictionary.h") 1.1201 + elif f.isEnum(): 1.1202 + # Need to see the actual definition of the enum, 1.1203 + # unfortunately. 1.1204 + headers.add(CGHeaders.getDeclarationFilename(f.inner)) 1.1205 + elif f.isCallback(): 1.1206 + # Callbacks always use strong refs, so we need to include 1.1207 + # the right header to be able to Release() in our inlined 1.1208 + # code. 1.1209 + headers.add(CGHeaders.getDeclarationFilename(f)) 1.1210 + elif f.isMozMap(): 1.1211 + headers.add("mozilla/dom/MozMap.h") 1.1212 + # And add headers for the type we're parametrized over 1.1213 + addHeadersForType(f.inner) 1.1214 + 1.1215 + for f in t.flatMemberTypes: 1.1216 + assert not f.nullable() 1.1217 + addHeadersForType(f) 1.1218 + 1.1219 + return (headers, implheaders, declarations, 1.1220 + CGList(SortedDictValues(unionStructs) + 1.1221 + SortedDictValues(owningUnionStructs), 1.1222 + "\n")) 1.1223 + 1.1224 + 1.1225 +def UnionConversions(descriptors, dictionaries, callbacks, config): 1.1226 + """ 1.1227 + Returns a CGThing to declare all union argument conversion helper structs. 1.1228 + """ 1.1229 + # Now find all the things we'll need as arguments because we 1.1230 + # need to unwrap them. 1.1231 + headers = set() 1.1232 + unionConversions = dict() 1.1233 + 1.1234 + for t, descriptor, dictionary in getAllTypes(descriptors, dictionaries, callbacks): 1.1235 + # Add info for the given type. descriptor and dictionary, if passed, are 1.1236 + # used to figure out what to do with interface types. 1.1237 + assert not descriptor or not dictionary 1.1238 + 1.1239 + t = t.unroll() 1.1240 + if not t.isUnion(): 1.1241 + continue 1.1242 + name = str(t) 1.1243 + if name not in unionConversions: 1.1244 + providers = getRelevantProviders(descriptor, config) 1.1245 + unionConversions[name] = CGUnionConversionStruct(t, providers[0]) 1.1246 + def addHeadersForType(f, providers): 1.1247 + f = f.unroll() 1.1248 + if f.isInterface(): 1.1249 + if f.isSpiderMonkeyInterface(): 1.1250 + headers.add("jsfriendapi.h") 1.1251 + headers.add("mozilla/dom/TypedArray.h") 1.1252 + elif f.inner.isExternal(): 1.1253 + providers = getRelevantProviders(descriptor, config) 1.1254 + for p in providers: 1.1255 + try: 1.1256 + typeDesc = p.getDescriptor(f.inner.identifier.name) 1.1257 + except NoSuchDescriptorError: 1.1258 + continue 1.1259 + headers.add(typeDesc.headerFile) 1.1260 + else: 1.1261 + headers.add(CGHeaders.getDeclarationFilename(f.inner)) 1.1262 + # Check for whether we have a possibly-XPConnect-implemented 1.1263 + # interface. If we do, the right descriptor will come from 1.1264 + # providers[0], because that would be the non-worker 1.1265 + # descriptor provider, if we have one at all. 1.1266 + if (f.isGeckoInterface() and 1.1267 + providers[0].getDescriptor(f.inner.identifier.name).hasXPConnectImpls): 1.1268 + headers.add("nsDOMQS.h") 1.1269 + elif f.isDictionary(): 1.1270 + headers.add(CGHeaders.getDeclarationFilename(f.inner)) 1.1271 + elif f.isPrimitive(): 1.1272 + headers.add("mozilla/dom/PrimitiveConversions.h") 1.1273 + elif f.isMozMap(): 1.1274 + headers.add("mozilla/dom/MozMap.h") 1.1275 + # And the internal type of the MozMap 1.1276 + addHeadersForType(f.inner, providers) 1.1277 + 1.1278 + for f in t.flatMemberTypes: 1.1279 + addHeadersForType(f, providers) 1.1280 + 1.1281 + return (headers, 1.1282 + CGWrapper(CGList(SortedDictValues(unionConversions), "\n"), 1.1283 + post="\n\n")) 1.1284 + 1.1285 + 1.1286 +class Argument(): 1.1287 + """ 1.1288 + A class for outputting the type and name of an argument 1.1289 + """ 1.1290 + def __init__(self, argType, name, default=None): 1.1291 + self.argType = argType 1.1292 + self.name = name 1.1293 + self.default = default 1.1294 + 1.1295 + def declare(self): 1.1296 + string = self.argType + ' ' + self.name 1.1297 + if self.default is not None: 1.1298 + string += " = " + self.default 1.1299 + return string 1.1300 + 1.1301 + def define(self): 1.1302 + return self.argType + ' ' + self.name 1.1303 + 1.1304 + 1.1305 +class CGAbstractMethod(CGThing): 1.1306 + """ 1.1307 + An abstract class for generating code for a method. Subclasses 1.1308 + should override definition_body to create the actual code. 1.1309 + 1.1310 + descriptor is the descriptor for the interface the method is associated with 1.1311 + 1.1312 + name is the name of the method as a string 1.1313 + 1.1314 + returnType is the IDLType of the return value 1.1315 + 1.1316 + args is a list of Argument objects 1.1317 + 1.1318 + inline should be True to generate an inline method, whose body is 1.1319 + part of the declaration. 1.1320 + 1.1321 + alwaysInline should be True to generate an inline method annotated with 1.1322 + MOZ_ALWAYS_INLINE. 1.1323 + 1.1324 + static should be True to generate a static method, which only has 1.1325 + a definition. 1.1326 + 1.1327 + If templateArgs is not None it should be a list of strings containing 1.1328 + template arguments, and the function will be templatized using those 1.1329 + arguments. 1.1330 + """ 1.1331 + def __init__(self, descriptor, name, returnType, args, inline=False, alwaysInline=False, static=False, templateArgs=None): 1.1332 + CGThing.__init__(self) 1.1333 + self.descriptor = descriptor 1.1334 + self.name = name 1.1335 + self.returnType = returnType 1.1336 + self.args = args 1.1337 + self.inline = inline 1.1338 + self.alwaysInline = alwaysInline 1.1339 + self.static = static 1.1340 + self.templateArgs = templateArgs 1.1341 + 1.1342 + def _argstring(self, declare): 1.1343 + return ', '.join([a.declare() if declare else a.define() for a in self.args]) 1.1344 + 1.1345 + def _template(self): 1.1346 + if self.templateArgs is None: 1.1347 + return '' 1.1348 + return 'template <%s>\n' % ', '.join(self.templateArgs) 1.1349 + 1.1350 + def _decorators(self): 1.1351 + decorators = [] 1.1352 + if self.alwaysInline: 1.1353 + decorators.append('MOZ_ALWAYS_INLINE') 1.1354 + elif self.inline: 1.1355 + decorators.append('inline') 1.1356 + if self.static: 1.1357 + decorators.append('static') 1.1358 + decorators.append(self.returnType) 1.1359 + maybeNewline = " " if self.inline else "\n" 1.1360 + return ' '.join(decorators) + maybeNewline 1.1361 + 1.1362 + def declare(self): 1.1363 + if self.inline: 1.1364 + return self._define(True) 1.1365 + return "%s%s%s(%s);\n" % (self._template(), self._decorators(), self.name, self._argstring(True)) 1.1366 + 1.1367 + def _define(self, fromDeclare=False): 1.1368 + return self.definition_prologue(fromDeclare) + self.definition_body() + self.definition_epilogue() 1.1369 + 1.1370 + def define(self): 1.1371 + return "" if self.inline else self._define() 1.1372 + 1.1373 + def definition_prologue(self, fromDeclare): 1.1374 + return "%s%s%s(%s)\n{\n" % (self._template(), self._decorators(), 1.1375 + self.name, self._argstring(fromDeclare)) 1.1376 + 1.1377 + def definition_epilogue(self): 1.1378 + return "}\n" 1.1379 + 1.1380 + def definition_body(self): 1.1381 + assert False # Override me! 1.1382 + 1.1383 + 1.1384 +class CGAbstractStaticMethod(CGAbstractMethod): 1.1385 + """ 1.1386 + Abstract base class for codegen of implementation-only (no 1.1387 + declaration) static methods. 1.1388 + """ 1.1389 + def __init__(self, descriptor, name, returnType, args): 1.1390 + CGAbstractMethod.__init__(self, descriptor, name, returnType, args, 1.1391 + inline=False, static=True) 1.1392 + 1.1393 + def declare(self): 1.1394 + # We only have implementation 1.1395 + return "" 1.1396 + 1.1397 + 1.1398 +class CGAbstractClassHook(CGAbstractStaticMethod): 1.1399 + """ 1.1400 + Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw 1.1401 + 'this' unwrapping as it assumes that the unwrapped type is always known. 1.1402 + """ 1.1403 + def __init__(self, descriptor, name, returnType, args): 1.1404 + CGAbstractStaticMethod.__init__(self, descriptor, name, returnType, 1.1405 + args) 1.1406 + 1.1407 + def definition_body_prologue(self): 1.1408 + return ("\n" # BOGUS extra blank line at start of function 1.1409 + " %s* self = UnwrapDOMObject<%s>(obj);\n" % 1.1410 + (self.descriptor.nativeType, self.descriptor.nativeType)) 1.1411 + 1.1412 + def definition_body(self): 1.1413 + return self.definition_body_prologue() + self.generate_code() 1.1414 + 1.1415 + def generate_code(self): 1.1416 + assert False # Override me! 1.1417 + 1.1418 + 1.1419 +class CGGetJSClassMethod(CGAbstractMethod): 1.1420 + def __init__(self, descriptor): 1.1421 + CGAbstractMethod.__init__(self, descriptor, 'GetJSClass', 'const JSClass*', 1.1422 + []) 1.1423 + 1.1424 + def definition_body(self): 1.1425 + return " return Class.ToJSClass();\n" 1.1426 + 1.1427 + 1.1428 +class CGAddPropertyHook(CGAbstractClassHook): 1.1429 + """ 1.1430 + A hook for addProperty, used to preserve our wrapper from GC. 1.1431 + """ 1.1432 + def __init__(self, descriptor): 1.1433 + args = [Argument('JSContext*', 'cx'), 1.1434 + Argument('JS::Handle<JSObject*>', 'obj'), 1.1435 + Argument('JS::Handle<jsid>', 'id'), 1.1436 + Argument('JS::MutableHandle<JS::Value>', 'vp')] 1.1437 + CGAbstractClassHook.__init__(self, descriptor, ADDPROPERTY_HOOK_NAME, 1.1438 + 'bool', args) 1.1439 + 1.1440 + def generate_code(self): 1.1441 + assert self.descriptor.wrapperCache 1.1442 + return indent(dedent(""" 1.1443 + // We don't want to preserve if we don't have a wrapper. 1.1444 + if (self->GetWrapperPreserveColor()) { 1.1445 + PreserveWrapper(self); 1.1446 + } 1.1447 + return true; 1.1448 + """)) 1.1449 + 1.1450 + 1.1451 +def DeferredFinalizeSmartPtr(descriptor): 1.1452 + if descriptor.nativeOwnership == 'owned': 1.1453 + smartPtr = 'nsAutoPtr' 1.1454 + else: 1.1455 + smartPtr = 'nsRefPtr' 1.1456 + return smartPtr 1.1457 + 1.1458 + 1.1459 +def finalizeHook(descriptor, hookName, freeOp): 1.1460 + finalize = "JSBindingFinalized<%s>::Finalized(self);\n" % descriptor.nativeType 1.1461 + if descriptor.wrapperCache: 1.1462 + finalize += "ClearWrapper(self, self);\n" 1.1463 + if descriptor.interface.getExtendedAttribute('OverrideBuiltins'): 1.1464 + finalize += "self->mExpandoAndGeneration.expando = JS::UndefinedValue();\n" 1.1465 + if descriptor.interface.getExtendedAttribute("Global"): 1.1466 + finalize += "mozilla::dom::FinalizeGlobal(CastToJSFreeOp(%s), obj);\n" % freeOp 1.1467 + finalize += ("AddForDeferredFinalization<%s, %s >(self);\n" % 1.1468 + (descriptor.nativeType, DeferredFinalizeSmartPtr(descriptor))) 1.1469 + return CGIfWrapper(CGGeneric(finalize), "self") 1.1470 + 1.1471 + 1.1472 +class CGClassFinalizeHook(CGAbstractClassHook): 1.1473 + """ 1.1474 + A hook for finalize, used to release our native object. 1.1475 + """ 1.1476 + def __init__(self, descriptor): 1.1477 + args = [Argument('js::FreeOp*', 'fop'), Argument('JSObject*', 'obj')] 1.1478 + CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME, 1.1479 + 'void', args) 1.1480 + 1.1481 + def generate_code(self): 1.1482 + return indent(finalizeHook(self.descriptor, self.name, self.args[0].name).define()) 1.1483 + 1.1484 + 1.1485 +class CGClassConstructor(CGAbstractStaticMethod): 1.1486 + """ 1.1487 + JS-visible constructor for our objects 1.1488 + """ 1.1489 + def __init__(self, descriptor, ctor, name=CONSTRUCT_HOOK_NAME): 1.1490 + args = [Argument('JSContext*', 'cx'), 1.1491 + Argument('unsigned', 'argc'), 1.1492 + Argument('JS::Value*', 'vp')] 1.1493 + CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args) 1.1494 + self._ctor = ctor 1.1495 + 1.1496 + def define(self): 1.1497 + if not self._ctor: 1.1498 + return "" 1.1499 + return CGAbstractStaticMethod.define(self) 1.1500 + 1.1501 + def definition_body(self): 1.1502 + return self.generate_code() 1.1503 + 1.1504 + def generate_code(self): 1.1505 + # [ChromeOnly] interfaces may only be constructed by chrome. 1.1506 + chromeOnlyCheck = "" 1.1507 + if isChromeOnly(self._ctor): 1.1508 + chromeOnlyCheck = dedent(""" 1.1509 + if (!nsContentUtils::ThreadsafeIsCallerChrome()) { 1.1510 + return ThrowingConstructor(cx, argc, vp); 1.1511 + } 1.1512 + 1.1513 + """) 1.1514 + 1.1515 + # Additionally, we want to throw if a caller does a bareword invocation 1.1516 + # of a constructor without |new|. We don't enforce this for chrome in 1.1517 + # realease builds to avoid the addon compat fallout of making that 1.1518 + # change. See bug 916644. 1.1519 + # 1.1520 + # Figure out the name of our constructor for error reporting purposes. 1.1521 + # For unnamed webidl constructors, identifier.name is "constructor" but 1.1522 + # the name JS sees is the interface name; for named constructors 1.1523 + # identifier.name is the actual name. 1.1524 + name = self._ctor.identifier.name 1.1525 + if name != "constructor": 1.1526 + ctorName = name 1.1527 + else: 1.1528 + ctorName = self.descriptor.interface.identifier.name 1.1529 + 1.1530 + preamble = fill( # BOGUS extra blank line at beginning of function body 1.1531 + """ 1.1532 + 1.1533 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.1534 + JS::Rooted<JSObject*> obj(cx, &args.callee()); 1.1535 + $*{chromeOnlyCheck} 1.1536 + bool mayInvoke = args.isConstructing(); 1.1537 + #ifdef RELEASE_BUILD 1.1538 + mayInvoke = mayInvoke || nsContentUtils::ThreadsafeIsCallerChrome(); 1.1539 + #endif // RELEASE_BUILD 1.1540 + if (!mayInvoke) { 1.1541 + // XXXbz wish I could get the name from the callee instead of 1.1542 + // Adding more relocations 1.1543 + return ThrowConstructorWithoutNew(cx, "${ctorName}"); 1.1544 + } 1.1545 + """, 1.1546 + chromeOnlyCheck=chromeOnlyCheck, 1.1547 + ctorName=ctorName) 1.1548 + 1.1549 + name = self._ctor.identifier.name 1.1550 + nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name)) 1.1551 + callGenerator = CGMethodCall(nativeName, True, self.descriptor, 1.1552 + self._ctor, isConstructor=True, 1.1553 + constructorName=ctorName) 1.1554 + return indent(preamble) + callGenerator.define() 1.1555 + 1.1556 + 1.1557 +# Encapsulate the constructor in a helper method to share genConstructorBody with CGJSImplMethod. 1.1558 +class CGConstructNavigatorObjectHelper(CGAbstractStaticMethod): 1.1559 + """ 1.1560 + Construct a new JS-implemented WebIDL DOM object, for use on navigator. 1.1561 + """ 1.1562 + def __init__(self, descriptor): 1.1563 + name = "ConstructNavigatorObjectHelper" 1.1564 + args = [Argument('JSContext*', 'cx'), 1.1565 + Argument('GlobalObject&', 'global'), 1.1566 + Argument('ErrorResult&', 'aRv')] 1.1567 + rtype = 'already_AddRefed<%s>' % descriptor.name 1.1568 + CGAbstractStaticMethod.__init__(self, descriptor, name, rtype, args) 1.1569 + 1.1570 + def definition_body(self): 1.1571 + return indent(genConstructorBody(self.descriptor)) 1.1572 + 1.1573 + 1.1574 +class CGConstructNavigatorObject(CGAbstractMethod): 1.1575 + """ 1.1576 + Wrap a JS-implemented WebIDL object into a JS value, for use on navigator. 1.1577 + """ 1.1578 + def __init__(self, descriptor): 1.1579 + name = 'ConstructNavigatorObject' 1.1580 + args = [Argument('JSContext*', 'aCx'), Argument('JS::Handle<JSObject*>', 'aObj')] 1.1581 + CGAbstractMethod.__init__(self, descriptor, name, 'JSObject*', args) 1.1582 + 1.1583 + def definition_body(self): 1.1584 + if not self.descriptor.interface.isJSImplemented(): 1.1585 + raise TypeError("Only JS-implemented classes are currently supported " 1.1586 + "on navigator. See bug 856820.") 1.1587 + return indent(fill( 1.1588 + """ 1.1589 + GlobalObject global(aCx, aObj); 1.1590 + if (global.Failed()) { 1.1591 + return nullptr; 1.1592 + } 1.1593 + ErrorResult rv; 1.1594 + JS::Rooted<JS::Value> v(aCx); 1.1595 + { // Scope to make sure |result| goes out of scope while |v| is rooted 1.1596 + nsRefPtr<mozilla::dom::${descriptorName}> result = ConstructNavigatorObjectHelper(aCx, global, rv); 1.1597 + rv.WouldReportJSException(); 1.1598 + if (rv.Failed()) { 1.1599 + ThrowMethodFailedWithDetails(aCx, rv, "${descriptorName}", "navigatorConstructor"); 1.1600 + return nullptr; 1.1601 + } 1.1602 + if (!WrapNewBindingObject(aCx, result, &v)) { 1.1603 + //XXX Assertion disabled for now, see bug 991271. 1.1604 + MOZ_ASSERT(true || JS_IsExceptionPending(aCx)); 1.1605 + return nullptr; 1.1606 + } 1.1607 + } 1.1608 + return &v.toObject(); 1.1609 + """, 1.1610 + descriptorName=self.descriptor.name)) 1.1611 + 1.1612 + 1.1613 +class CGClassConstructHookHolder(CGGeneric): 1.1614 + def __init__(self, descriptor): 1.1615 + if descriptor.interface.ctor(): 1.1616 + constructHook = CONSTRUCT_HOOK_NAME 1.1617 + else: 1.1618 + constructHook = "ThrowingConstructor" 1.1619 + CGGeneric.__init__(self, fill( 1.1620 + """ 1.1621 + static const JSNativeHolder ${CONSTRUCT_HOOK_NAME}_holder = { 1.1622 + ${constructHook}, 1.1623 + ${hooks} 1.1624 + }; 1.1625 + """, 1.1626 + CONSTRUCT_HOOK_NAME=CONSTRUCT_HOOK_NAME, 1.1627 + constructHook=constructHook, 1.1628 + hooks=NativePropertyHooks(descriptor))) 1.1629 + 1.1630 + 1.1631 +def NamedConstructorName(m): 1.1632 + return '_' + m.identifier.name 1.1633 + 1.1634 + 1.1635 +class CGNamedConstructors(CGThing): 1.1636 + def __init__(self, descriptor): 1.1637 + self.descriptor = descriptor 1.1638 + CGThing.__init__(self) 1.1639 + 1.1640 + def declare(self): 1.1641 + return "" 1.1642 + 1.1643 + def define(self): 1.1644 + if len(self.descriptor.interface.namedConstructors) == 0: 1.1645 + return "" 1.1646 + 1.1647 + constructorID = "constructors::id::" 1.1648 + if self.descriptor.interface.hasInterfaceObject(): 1.1649 + constructorID += self.descriptor.name 1.1650 + else: 1.1651 + constructorID += "_ID_Count" 1.1652 + 1.1653 + namedConstructors = "" 1.1654 + for n in self.descriptor.interface.namedConstructors: 1.1655 + namedConstructors += ( 1.1656 + "{ \"%s\", { %s, &sNamedConstructorNativePropertyHooks }, %i },\n" % 1.1657 + (n.identifier.name, NamedConstructorName(n), methodLength(n))) 1.1658 + 1.1659 + return fill( 1.1660 + """ 1.1661 + const NativePropertyHooks sNamedConstructorNativePropertyHooks = { 1.1662 + nullptr, 1.1663 + nullptr, 1.1664 + { nullptr, nullptr }, 1.1665 + prototypes::id::${name}, 1.1666 + ${constructorID}, 1.1667 + nullptr 1.1668 + }; 1.1669 + 1.1670 + static const NamedConstructor namedConstructors[] = { 1.1671 + $*{namedConstructors} 1.1672 + { nullptr, { nullptr, nullptr }, 0 } 1.1673 + }; 1.1674 + """, 1.1675 + name=self.descriptor.name, 1.1676 + constructorID=constructorID, 1.1677 + namedConstructors=namedConstructors) 1.1678 + 1.1679 + 1.1680 +class CGClassHasInstanceHook(CGAbstractStaticMethod): 1.1681 + def __init__(self, descriptor): 1.1682 + args = [Argument('JSContext*', 'cx'), 1.1683 + Argument('JS::Handle<JSObject*>', 'obj'), 1.1684 + Argument('JS::MutableHandle<JS::Value>', 'vp'), 1.1685 + Argument('bool*', 'bp')] 1.1686 + CGAbstractStaticMethod.__init__(self, descriptor, HASINSTANCE_HOOK_NAME, 1.1687 + 'bool', args) 1.1688 + 1.1689 + def define(self): 1.1690 + if not NeedsGeneratedHasInstance(self.descriptor): 1.1691 + return "" 1.1692 + return CGAbstractStaticMethod.define(self) 1.1693 + 1.1694 + def definition_body(self): 1.1695 + return self.generate_code() 1.1696 + 1.1697 + def generate_code(self): 1.1698 + # BOGUS extra blank line at start of function 1.1699 + header = dedent(""" 1.1700 + 1.1701 + if (!vp.isObject()) { 1.1702 + *bp = false; 1.1703 + return true; 1.1704 + } 1.1705 + 1.1706 + JS::Rooted<JSObject*> instance(cx, &vp.toObject()); 1.1707 + """) 1.1708 + if self.descriptor.interface.hasInterfacePrototypeObject(): 1.1709 + return indent( 1.1710 + header + 1.1711 + fill( 1.1712 + """ 1.1713 + 1.1714 + static_assert(IsBaseOf<nsISupports, ${nativeType}>::value, 1.1715 + "HasInstance only works for nsISupports-based classes."); 1.1716 + 1.1717 + bool ok = InterfaceHasInstance(cx, obj, instance, bp); 1.1718 + if (!ok || *bp) { 1.1719 + return ok; 1.1720 + } 1.1721 + 1.1722 + // FIXME Limit this to chrome by checking xpc::AccessCheck::isChrome(obj). 1.1723 + nsISupports* native = 1.1724 + nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, 1.1725 + js::UncheckedUnwrap(instance)); 1.1726 + nsCOMPtr<nsIDOM${name}> qiResult = do_QueryInterface(native); 1.1727 + *bp = !!qiResult; 1.1728 + return true; 1.1729 + 1.1730 + """, # BOGUS extra blank line at end of function 1.1731 + nativeType=self.descriptor.nativeType, 1.1732 + name=self.descriptor.interface.identifier.name)) 1.1733 + 1.1734 + hasInstanceCode = dedent(""" 1.1735 + 1.1736 + const DOMClass* domClass = GetDOMClass(js::UncheckedUnwrap(instance)); 1.1737 + *bp = false; 1.1738 + if (!domClass) { 1.1739 + // Not a DOM object, so certainly not an instance of this interface 1.1740 + return true; 1.1741 + } 1.1742 + """) 1.1743 + if self.descriptor.interface.identifier.name == "ChromeWindow": 1.1744 + setBp = "*bp = UnwrapDOMObject<nsGlobalWindow>(js::UncheckedUnwrap(instance))->IsChromeWindow()" 1.1745 + else: 1.1746 + setBp = "*bp = true" 1.1747 + # Sort interaces implementing self by name so we get stable output. 1.1748 + for iface in sorted(self.descriptor.interface.interfacesImplementingSelf, 1.1749 + key=lambda iface: iface.identifier.name): 1.1750 + hasInstanceCode += fill( 1.1751 + """ 1.1752 + 1.1753 + if (domClass->mInterfaceChain[PrototypeTraits<prototypes::id::${name}>::Depth] == prototypes::id::${name}) { 1.1754 + ${setBp}; 1.1755 + return true; 1.1756 + } 1.1757 + """, 1.1758 + name=iface.identifier.name, 1.1759 + setBp=setBp) 1.1760 + hasInstanceCode += "return true;\n" 1.1761 + return indent(header + hasInstanceCode) 1.1762 + 1.1763 + 1.1764 +def isChromeOnly(m): 1.1765 + return m.getExtendedAttribute("ChromeOnly") 1.1766 + 1.1767 + 1.1768 +def getAvailableInTestFunc(obj): 1.1769 + availableIn = obj.getExtendedAttribute("AvailableIn") 1.1770 + if availableIn is None: 1.1771 + return None 1.1772 + assert isinstance(availableIn, list) and len(availableIn) == 1 1.1773 + if availableIn[0] == "PrivilegedApps": 1.1774 + return "IsInPrivilegedApp" 1.1775 + if availableIn[0] == "CertifiedApps": 1.1776 + return "IsInCertifiedApp" 1.1777 + raise TypeError("Unknown AvailableIn value '%s'" % availableIn[0]) 1.1778 + 1.1779 + 1.1780 +class MemberCondition: 1.1781 + """ 1.1782 + An object representing the condition for a member to actually be 1.1783 + exposed. Any of pref, func, and available can be None. If not 1.1784 + None, they should be strings that have the pref name (for "pref") 1.1785 + or function name (for "func" and "available"). 1.1786 + """ 1.1787 + def __init__(self, pref, func, available=None): 1.1788 + assert pref is None or isinstance(pref, str) 1.1789 + assert func is None or isinstance(func, str) 1.1790 + assert available is None or isinstance(available, str) 1.1791 + self.pref = pref 1.1792 + 1.1793 + def toFuncPtr(val): 1.1794 + if val is None: 1.1795 + return "nullptr" 1.1796 + return "&" + val 1.1797 + self.func = toFuncPtr(func) 1.1798 + self.available = toFuncPtr(available) 1.1799 + 1.1800 + def __eq__(self, other): 1.1801 + return (self.pref == other.pref and self.func == other.func and 1.1802 + self.available == other.available) 1.1803 + 1.1804 + def __ne__(self, other): 1.1805 + return not self.__eq__(other) 1.1806 + 1.1807 + 1.1808 +class PropertyDefiner: 1.1809 + """ 1.1810 + A common superclass for defining things on prototype objects. 1.1811 + 1.1812 + Subclasses should implement generateArray to generate the actual arrays of 1.1813 + things we're defining. They should also set self.chrome to the list of 1.1814 + things only exposed to chrome and self.regular to the list of things exposed 1.1815 + to both chrome and web pages. 1.1816 + """ 1.1817 + def __init__(self, descriptor, name): 1.1818 + self.descriptor = descriptor 1.1819 + self.name = name 1.1820 + # self.prefCacheData will store an array of (prefname, bool*) 1.1821 + # pairs for our bool var caches. generateArray will fill it 1.1822 + # in as needed. 1.1823 + self.prefCacheData = [] 1.1824 + 1.1825 + def hasChromeOnly(self): 1.1826 + return len(self.chrome) > 0 1.1827 + 1.1828 + def hasNonChromeOnly(self): 1.1829 + return len(self.regular) > 0 1.1830 + 1.1831 + def variableName(self, chrome): 1.1832 + if chrome: 1.1833 + if self.hasChromeOnly(): 1.1834 + return "sChrome" + self.name 1.1835 + else: 1.1836 + if self.hasNonChromeOnly(): 1.1837 + return "s" + self.name 1.1838 + return "nullptr" 1.1839 + 1.1840 + def usedForXrays(self): 1.1841 + # No Xrays in workers. 1.1842 + return not self.descriptor.workers 1.1843 + 1.1844 + def __str__(self): 1.1845 + # We only need to generate id arrays for things that will end 1.1846 + # up used via ResolveProperty or EnumerateProperties. 1.1847 + str = self.generateArray(self.regular, self.variableName(False), 1.1848 + self.usedForXrays()) 1.1849 + if self.hasChromeOnly(): 1.1850 + str += self.generateArray(self.chrome, self.variableName(True), 1.1851 + self.usedForXrays()) 1.1852 + return str 1.1853 + 1.1854 + @staticmethod 1.1855 + def getStringAttr(member, name): 1.1856 + attr = member.getExtendedAttribute(name) 1.1857 + if attr is None: 1.1858 + return None 1.1859 + # It's a list of strings 1.1860 + assert len(attr) == 1 1.1861 + assert attr[0] is not None 1.1862 + return attr[0] 1.1863 + 1.1864 + @staticmethod 1.1865 + def getControllingCondition(interfaceMember): 1.1866 + return MemberCondition(PropertyDefiner.getStringAttr(interfaceMember, 1.1867 + "Pref"), 1.1868 + PropertyDefiner.getStringAttr(interfaceMember, 1.1869 + "Func"), 1.1870 + getAvailableInTestFunc(interfaceMember)) 1.1871 + 1.1872 + def generatePrefableArray(self, array, name, specTemplate, specTerminator, 1.1873 + specType, getCondition, getDataTuple, doIdArrays): 1.1874 + """ 1.1875 + This method generates our various arrays. 1.1876 + 1.1877 + array is an array of interface members as passed to generateArray 1.1878 + 1.1879 + name is the name as passed to generateArray 1.1880 + 1.1881 + specTemplate is a template for each entry of the spec array 1.1882 + 1.1883 + specTerminator is a terminator for the spec array (inserted every time 1.1884 + our controlling pref changes and at the end of the array) 1.1885 + 1.1886 + specType is the actual typename of our spec 1.1887 + 1.1888 + getCondition is a callback function that takes an array entry and 1.1889 + returns the corresponding MemberCondition. 1.1890 + 1.1891 + getDataTuple is a callback function that takes an array entry and 1.1892 + returns a tuple suitable for substitution into specTemplate. 1.1893 + """ 1.1894 + 1.1895 + # We want to generate a single list of specs, but with specTerminator 1.1896 + # inserted at every point where the pref name controlling the member 1.1897 + # changes. That will make sure the order of the properties as exposed 1.1898 + # on the interface and interface prototype objects does not change when 1.1899 + # pref control is added to members while still allowing us to define all 1.1900 + # the members in the smallest number of JSAPI calls. 1.1901 + assert len(array) != 0 1.1902 + lastCondition = getCondition(array[0]) # So we won't put a specTerminator 1.1903 + # at the very front of the list. 1.1904 + specs = [] 1.1905 + prefableSpecs = [] 1.1906 + 1.1907 + prefableTemplate = ' { true, %s, %s, &%s[%d] }' 1.1908 + prefCacheTemplate = '&%s[%d].enabled' 1.1909 + 1.1910 + def switchToCondition(props, condition): 1.1911 + # Remember the info about where our pref-controlled 1.1912 + # booleans live. 1.1913 + if condition.pref is not None: 1.1914 + props.prefCacheData.append( 1.1915 + (condition.pref, 1.1916 + prefCacheTemplate % (name, len(prefableSpecs)))) 1.1917 + # Set up pointers to the new sets of specs inside prefableSpecs 1.1918 + prefableSpecs.append(prefableTemplate % 1.1919 + (condition.func, 1.1920 + condition.available, 1.1921 + name + "_specs", len(specs))) 1.1922 + 1.1923 + switchToCondition(self, lastCondition) 1.1924 + 1.1925 + for member in array: 1.1926 + curCondition = getCondition(member) 1.1927 + if lastCondition != curCondition: 1.1928 + # Terminate previous list 1.1929 + specs.append(specTerminator) 1.1930 + # And switch to our new pref 1.1931 + switchToCondition(self, curCondition) 1.1932 + lastCondition = curCondition 1.1933 + # And the actual spec 1.1934 + specs.append(specTemplate % getDataTuple(member)) 1.1935 + specs.append(specTerminator) 1.1936 + prefableSpecs.append(" { false, nullptr }") 1.1937 + 1.1938 + specType = "const " + specType 1.1939 + arrays = fill( 1.1940 + """ 1.1941 + static ${specType} ${name}_specs[] = { 1.1942 + ${specs} 1.1943 + }; 1.1944 + 1.1945 + // Can't be const because the pref-enabled boolean needs to be writable 1.1946 + static Prefable<${specType}> ${name}[] = { 1.1947 + ${prefableSpecs} 1.1948 + }; 1.1949 + 1.1950 + """, 1.1951 + specType=specType, 1.1952 + name=name, 1.1953 + specs=',\n'.join(specs), 1.1954 + prefableSpecs=',\n'.join(prefableSpecs)) 1.1955 + if doIdArrays: 1.1956 + arrays += "static jsid %s_ids[%i];\n\n" % (name, len(specs)) 1.1957 + return arrays 1.1958 + 1.1959 + 1.1960 +# The length of a method is the minimum of the lengths of the 1.1961 +# argument lists of all its overloads. 1.1962 +def overloadLength(arguments): 1.1963 + i = len(arguments) 1.1964 + while i > 0 and arguments[i - 1].optional: 1.1965 + i -= 1 1.1966 + return i 1.1967 + 1.1968 + 1.1969 +def methodLength(method): 1.1970 + signatures = method.signatures() 1.1971 + return min(overloadLength(arguments) for retType, arguments in signatures) 1.1972 + 1.1973 + 1.1974 +class MethodDefiner(PropertyDefiner): 1.1975 + """ 1.1976 + A class for defining methods on a prototype object. 1.1977 + """ 1.1978 + def __init__(self, descriptor, name, static): 1.1979 + PropertyDefiner.__init__(self, descriptor, name) 1.1980 + 1.1981 + # FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=772822 1.1982 + # We should be able to check for special operations without an 1.1983 + # identifier. For now we check if the name starts with __ 1.1984 + 1.1985 + # Ignore non-static methods for interfaces without a proto object 1.1986 + if descriptor.interface.hasInterfacePrototypeObject() or static: 1.1987 + methods = [m for m in descriptor.interface.members if 1.1988 + m.isMethod() and m.isStatic() == static and 1.1989 + not m.isIdentifierLess()] 1.1990 + else: 1.1991 + methods = [] 1.1992 + self.chrome = [] 1.1993 + self.regular = [] 1.1994 + for m in methods: 1.1995 + if m.identifier.name == 'queryInterface': 1.1996 + if self.descriptor.workers: 1.1997 + continue 1.1998 + if m.isStatic(): 1.1999 + raise TypeError("Legacy queryInterface member shouldn't be static") 1.2000 + signatures = m.signatures() 1.2001 + 1.2002 + def argTypeIsIID(arg): 1.2003 + return arg.type.inner.isExternal() and arg.type.inner.identifier.name == 'IID' 1.2004 + if len(signatures) > 1 or len(signatures[0][1]) > 1 or not argTypeIsIID(signatures[0][1][0]): 1.2005 + raise TypeError("There should be only one queryInterface method with 1 argument of type IID") 1.2006 + 1.2007 + # Make sure to not stick QueryInterface on abstract interfaces that 1.2008 + # have hasXPConnectImpls (like EventTarget). So only put it on 1.2009 + # interfaces that are concrete and all of whose ancestors are abstract. 1.2010 + def allAncestorsAbstract(iface): 1.2011 + if not iface.parent: 1.2012 + return True 1.2013 + desc = self.descriptor.getDescriptor(iface.parent.identifier.name) 1.2014 + if desc.concrete: 1.2015 + return False 1.2016 + return allAncestorsAbstract(iface.parent) 1.2017 + if (not self.descriptor.interface.hasInterfacePrototypeObject() or 1.2018 + not self.descriptor.concrete or 1.2019 + not allAncestorsAbstract(self.descriptor.interface)): 1.2020 + raise TypeError("QueryInterface is only supported on " 1.2021 + "interfaces that are concrete and all " 1.2022 + "of whose ancestors are abstract: " + 1.2023 + self.descriptor.name) 1.2024 + condition = "WantsQueryInterface<%s>::Enabled" % descriptor.nativeType 1.2025 + self.regular.append({ 1.2026 + "name": 'QueryInterface', 1.2027 + "methodInfo": False, 1.2028 + "length": 1, 1.2029 + "flags": "0", 1.2030 + "condition": MemberCondition(None, condition) 1.2031 + }) 1.2032 + continue 1.2033 + 1.2034 + method = { 1.2035 + "name": m.identifier.name, 1.2036 + "methodInfo": not m.isStatic(), 1.2037 + "length": methodLength(m), 1.2038 + "flags": "JSPROP_ENUMERATE", 1.2039 + "condition": PropertyDefiner.getControllingCondition(m), 1.2040 + "allowCrossOriginThis": m.getExtendedAttribute("CrossOriginCallable"), 1.2041 + "returnsPromise": m.returnsPromise() 1.2042 + } 1.2043 + if isChromeOnly(m): 1.2044 + self.chrome.append(method) 1.2045 + else: 1.2046 + self.regular.append(method) 1.2047 + 1.2048 + # FIXME Check for an existing iterator on the interface first. 1.2049 + if any(m.isGetter() and m.isIndexed() for m in methods): 1.2050 + self.regular.append({ 1.2051 + "name": "@@iterator", 1.2052 + "methodInfo": False, 1.2053 + "selfHostedName": "ArrayValues", 1.2054 + "length": 0, 1.2055 + "flags": "JSPROP_ENUMERATE", 1.2056 + "condition": MemberCondition(None, None) 1.2057 + }) 1.2058 + 1.2059 + if not static: 1.2060 + stringifier = descriptor.operations['Stringifier'] 1.2061 + if stringifier: 1.2062 + toStringDesc = { 1.2063 + "name": "toString", 1.2064 + "nativeName": stringifier.identifier.name, 1.2065 + "length": 0, 1.2066 + "flags": "JSPROP_ENUMERATE", 1.2067 + "condition": PropertyDefiner.getControllingCondition(stringifier) 1.2068 + } 1.2069 + if isChromeOnly(stringifier): 1.2070 + self.chrome.append(toStringDesc) 1.2071 + else: 1.2072 + self.regular.append(toStringDesc) 1.2073 + jsonifier = descriptor.operations['Jsonifier'] 1.2074 + if jsonifier: 1.2075 + toJSONDesc = { 1.2076 + "name": "toJSON", 1.2077 + "nativeName": jsonifier.identifier.name, 1.2078 + "length": 0, 1.2079 + "flags": "JSPROP_ENUMERATE", 1.2080 + "condition": PropertyDefiner.getControllingCondition(jsonifier) 1.2081 + } 1.2082 + if isChromeOnly(jsonifier): 1.2083 + self.chrome.append(toJSONDesc) 1.2084 + else: 1.2085 + self.regular.append(toJSONDesc) 1.2086 + elif (descriptor.interface.isJSImplemented() and 1.2087 + descriptor.interface.hasInterfaceObject()): 1.2088 + self.chrome.append({ 1.2089 + "name": '_create', 1.2090 + "nativeName": ("%s::_Create" % descriptor.name), 1.2091 + "methodInfo": False, 1.2092 + "length": 2, 1.2093 + "flags": "0", 1.2094 + "condition": MemberCondition(None, None) 1.2095 + }) 1.2096 + 1.2097 + if static: 1.2098 + if not descriptor.interface.hasInterfaceObject(): 1.2099 + # static methods go on the interface object 1.2100 + assert not self.hasChromeOnly() and not self.hasNonChromeOnly() 1.2101 + else: 1.2102 + if not descriptor.interface.hasInterfacePrototypeObject(): 1.2103 + # non-static methods go on the interface prototype object 1.2104 + assert not self.hasChromeOnly() and not self.hasNonChromeOnly() 1.2105 + 1.2106 + def generateArray(self, array, name, doIdArrays): 1.2107 + if len(array) == 0: 1.2108 + return "" 1.2109 + 1.2110 + def condition(m): 1.2111 + return m["condition"] 1.2112 + 1.2113 + def specData(m): 1.2114 + if "selfHostedName" in m: 1.2115 + selfHostedName = '"%s"' % m["selfHostedName"] 1.2116 + assert not m.get("methodInfo", True) 1.2117 + accessor = "nullptr" 1.2118 + jitinfo = "nullptr" 1.2119 + else: 1.2120 + selfHostedName = "nullptr" 1.2121 + accessor = m.get("nativeName", m["name"]) 1.2122 + if m.get("methodInfo", True): 1.2123 + # Cast this in case the methodInfo is a 1.2124 + # JSTypedMethodJitInfo. 1.2125 + jitinfo = ("reinterpret_cast<const JSJitInfo*>(&%s_methodinfo)" % accessor) 1.2126 + if m.get("allowCrossOriginThis", False): 1.2127 + if m.get("returnsPromise", False): 1.2128 + raise TypeError("%s returns a Promise but should " 1.2129 + "be allowed cross-origin?" % 1.2130 + accessor) 1.2131 + accessor = "genericCrossOriginMethod" 1.2132 + elif self.descriptor.needsSpecialGenericOps(): 1.2133 + if m.get("returnsPromise", False): 1.2134 + raise TypeError("%s returns a Promise but needs " 1.2135 + "special generic ops?" % 1.2136 + accessor) 1.2137 + accessor = "genericMethod" 1.2138 + elif m.get("returnsPromise", False): 1.2139 + accessor = "GenericPromiseReturningBindingMethod" 1.2140 + else: 1.2141 + accessor = "GenericBindingMethod" 1.2142 + else: 1.2143 + if m.get("returnsPromise", False): 1.2144 + jitinfo = "&%s_methodinfo" % accessor 1.2145 + accessor = "StaticMethodPromiseWrapper" 1.2146 + else: 1.2147 + jitinfo = "nullptr" 1.2148 + 1.2149 + return (m["name"], accessor, jitinfo, m["length"], m["flags"], selfHostedName) 1.2150 + 1.2151 + return self.generatePrefableArray( 1.2152 + array, name, 1.2153 + ' JS_FNSPEC("%s", %s, %s, %s, %s, %s)', 1.2154 + ' JS_FS_END', 1.2155 + 'JSFunctionSpec', 1.2156 + condition, specData, doIdArrays) 1.2157 + 1.2158 + 1.2159 +class AttrDefiner(PropertyDefiner): 1.2160 + def __init__(self, descriptor, name, static, unforgeable=False): 1.2161 + assert not (static and unforgeable) 1.2162 + PropertyDefiner.__init__(self, descriptor, name) 1.2163 + self.name = name 1.2164 + # Ignore non-static attributes for interfaces without a proto object 1.2165 + if descriptor.interface.hasInterfacePrototypeObject() or static: 1.2166 + attributes = [m for m in descriptor.interface.members if 1.2167 + m.isAttr() and m.isStatic() == static and 1.2168 + m.isUnforgeable() == unforgeable] 1.2169 + else: 1.2170 + attributes = [] 1.2171 + self.chrome = [m for m in attributes if isChromeOnly(m)] 1.2172 + self.regular = [m for m in attributes if not isChromeOnly(m)] 1.2173 + self.static = static 1.2174 + self.unforgeable = unforgeable 1.2175 + 1.2176 + if static: 1.2177 + if not descriptor.interface.hasInterfaceObject(): 1.2178 + # static attributes go on the interface object 1.2179 + assert not self.hasChromeOnly() and not self.hasNonChromeOnly() 1.2180 + else: 1.2181 + if not descriptor.interface.hasInterfacePrototypeObject(): 1.2182 + # non-static attributes go on the interface prototype object 1.2183 + assert not self.hasChromeOnly() and not self.hasNonChromeOnly() 1.2184 + 1.2185 + def generateArray(self, array, name, doIdArrays): 1.2186 + if len(array) == 0: 1.2187 + return "" 1.2188 + 1.2189 + def flags(attr): 1.2190 + unforgeable = " | JSPROP_PERMANENT" if self.unforgeable else "" 1.2191 + return ("JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS" + 1.2192 + unforgeable) 1.2193 + 1.2194 + def getter(attr): 1.2195 + if self.static: 1.2196 + accessor = 'get_' + attr.identifier.name 1.2197 + jitinfo = "nullptr" 1.2198 + else: 1.2199 + if attr.hasLenientThis(): 1.2200 + accessor = "genericLenientGetter" 1.2201 + elif attr.getExtendedAttribute("CrossOriginReadable"): 1.2202 + accessor = "genericCrossOriginGetter" 1.2203 + elif self.descriptor.needsSpecialGenericOps(): 1.2204 + accessor = "genericGetter" 1.2205 + else: 1.2206 + accessor = "GenericBindingGetter" 1.2207 + jitinfo = "&%s_getterinfo" % attr.identifier.name 1.2208 + return "{ { JS_CAST_NATIVE_TO(%s, JSPropertyOp), %s } }" % \ 1.2209 + (accessor, jitinfo) 1.2210 + 1.2211 + def setter(attr): 1.2212 + if (attr.readonly and 1.2213 + attr.getExtendedAttribute("PutForwards") is None and 1.2214 + attr.getExtendedAttribute("Replaceable") is None): 1.2215 + return "JSOP_NULLWRAPPER" 1.2216 + if self.static: 1.2217 + accessor = 'set_' + attr.identifier.name 1.2218 + jitinfo = "nullptr" 1.2219 + else: 1.2220 + if attr.hasLenientThis(): 1.2221 + accessor = "genericLenientSetter" 1.2222 + elif attr.getExtendedAttribute("CrossOriginWritable"): 1.2223 + accessor = "genericCrossOriginSetter" 1.2224 + elif self.descriptor.needsSpecialGenericOps(): 1.2225 + accessor = "genericSetter" 1.2226 + else: 1.2227 + accessor = "GenericBindingSetter" 1.2228 + jitinfo = "&%s_setterinfo" % attr.identifier.name 1.2229 + return "{ { JS_CAST_NATIVE_TO(%s, JSStrictPropertyOp), %s } }" % \ 1.2230 + (accessor, jitinfo) 1.2231 + 1.2232 + def specData(attr): 1.2233 + return (attr.identifier.name, flags(attr), getter(attr), 1.2234 + setter(attr)) 1.2235 + 1.2236 + return self.generatePrefableArray( 1.2237 + array, name, 1.2238 + ' { "%s", %s, %s, %s}', 1.2239 + ' JS_PS_END', 1.2240 + 'JSPropertySpec', 1.2241 + PropertyDefiner.getControllingCondition, specData, doIdArrays) 1.2242 + 1.2243 + 1.2244 +class ConstDefiner(PropertyDefiner): 1.2245 + """ 1.2246 + A class for definining constants on the interface object 1.2247 + """ 1.2248 + def __init__(self, descriptor, name): 1.2249 + PropertyDefiner.__init__(self, descriptor, name) 1.2250 + self.name = name 1.2251 + constants = [m for m in descriptor.interface.members if m.isConst()] 1.2252 + self.chrome = [m for m in constants if isChromeOnly(m)] 1.2253 + self.regular = [m for m in constants if not isChromeOnly(m)] 1.2254 + 1.2255 + def generateArray(self, array, name, doIdArrays): 1.2256 + if len(array) == 0: 1.2257 + return "" 1.2258 + 1.2259 + def specData(const): 1.2260 + return (const.identifier.name, 1.2261 + convertConstIDLValueToJSVal(const.value)) 1.2262 + 1.2263 + return self.generatePrefableArray( 1.2264 + array, name, 1.2265 + ' { "%s", %s }', 1.2266 + ' { 0, JS::UndefinedValue() }', 1.2267 + 'ConstantSpec', 1.2268 + PropertyDefiner.getControllingCondition, specData, doIdArrays) 1.2269 + 1.2270 + 1.2271 +class PropertyArrays(): 1.2272 + def __init__(self, descriptor): 1.2273 + self.staticMethods = MethodDefiner(descriptor, "StaticMethods", 1.2274 + static=True) 1.2275 + self.staticAttrs = AttrDefiner(descriptor, "StaticAttributes", 1.2276 + static=True) 1.2277 + self.methods = MethodDefiner(descriptor, "Methods", static=False) 1.2278 + self.attrs = AttrDefiner(descriptor, "Attributes", static=False) 1.2279 + self.unforgeableAttrs = AttrDefiner(descriptor, "UnforgeableAttributes", 1.2280 + static=False, unforgeable=True) 1.2281 + self.consts = ConstDefiner(descriptor, "Constants") 1.2282 + 1.2283 + @staticmethod 1.2284 + def arrayNames(): 1.2285 + return ["staticMethods", "staticAttrs", "methods", "attrs", 1.2286 + "unforgeableAttrs", "consts"] 1.2287 + 1.2288 + def hasChromeOnly(self): 1.2289 + return any(getattr(self, a).hasChromeOnly() for a in self.arrayNames()) 1.2290 + 1.2291 + def hasNonChromeOnly(self): 1.2292 + return any(getattr(self, a).hasNonChromeOnly() for a in self.arrayNames()) 1.2293 + 1.2294 + def __str__(self): 1.2295 + define = "" 1.2296 + for array in self.arrayNames(): 1.2297 + define += str(getattr(self, array)) 1.2298 + return define 1.2299 + 1.2300 + 1.2301 +class CGNativeProperties(CGList): 1.2302 + def __init__(self, descriptor, properties): 1.2303 + def generateNativeProperties(name, chrome): 1.2304 + def check(p): 1.2305 + return p.hasChromeOnly() if chrome else p.hasNonChromeOnly() 1.2306 + 1.2307 + nativeProps = [] 1.2308 + for array in properties.arrayNames(): 1.2309 + propertyArray = getattr(properties, array) 1.2310 + if check(propertyArray): 1.2311 + if propertyArray.usedForXrays(): 1.2312 + ids = "%(name)s_ids" 1.2313 + else: 1.2314 + ids = "nullptr" 1.2315 + props = "%(name)s, " + ids + ", %(name)s_specs" 1.2316 + props = (props % {'name': propertyArray.variableName(chrome)}) 1.2317 + else: 1.2318 + props = "nullptr, nullptr, nullptr" 1.2319 + nativeProps.append(CGGeneric(props)) 1.2320 + return CGWrapper(CGIndenter(CGList(nativeProps, ",\n")), 1.2321 + pre="static const NativeProperties %s = {\n" % name, 1.2322 + post="\n};\n") 1.2323 + 1.2324 + nativeProperties = [] 1.2325 + if properties.hasNonChromeOnly(): 1.2326 + nativeProperties.append( 1.2327 + generateNativeProperties("sNativeProperties", False)) 1.2328 + if properties.hasChromeOnly(): 1.2329 + nativeProperties.append( 1.2330 + generateNativeProperties("sChromeOnlyNativeProperties", True)) 1.2331 + 1.2332 + CGList.__init__(self, nativeProperties, "\n") 1.2333 + 1.2334 + def declare(self): 1.2335 + return "" 1.2336 + 1.2337 + def define(self): 1.2338 + # BOGUSly strip off a newline 1.2339 + return CGList.define(self).rstrip() 1.2340 + 1.2341 + 1.2342 +class CGCreateInterfaceObjectsMethod(CGAbstractMethod): 1.2343 + """ 1.2344 + Generate the CreateInterfaceObjects method for an interface descriptor. 1.2345 + 1.2346 + properties should be a PropertyArrays instance. 1.2347 + """ 1.2348 + def __init__(self, descriptor, properties): 1.2349 + args = [Argument('JSContext*', 'aCx'), 1.2350 + Argument('JS::Handle<JSObject*>', 'aGlobal'), 1.2351 + Argument('ProtoAndIfaceCache&', 'aProtoAndIfaceCache'), 1.2352 + Argument('bool', 'aDefineOnGlobal')] 1.2353 + CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args) 1.2354 + self.properties = properties 1.2355 + 1.2356 + def definition_body(self): 1.2357 + if len(self.descriptor.prototypeChain) == 1: 1.2358 + parentProtoType = "Rooted" 1.2359 + if self.descriptor.interface.getExtendedAttribute("ArrayClass"): 1.2360 + getParentProto = "aCx, JS_GetArrayPrototype(aCx, aGlobal)" 1.2361 + else: 1.2362 + getParentProto = "aCx, JS_GetObjectPrototype(aCx, aGlobal)" 1.2363 + else: 1.2364 + parentProtoName = self.descriptor.prototypeChain[-2] 1.2365 + parentDesc = self.descriptor.getDescriptor(parentProtoName) 1.2366 + if parentDesc.workers: 1.2367 + parentProtoName += '_workers' 1.2368 + getParentProto = ("%s::GetProtoObject(aCx, aGlobal)" % 1.2369 + toBindingNamespace(parentProtoName)) 1.2370 + parentProtoType = "Handle" 1.2371 + 1.2372 + parentWithInterfaceObject = self.descriptor.interface.parent 1.2373 + while (parentWithInterfaceObject and 1.2374 + not parentWithInterfaceObject.hasInterfaceObject()): 1.2375 + parentWithInterfaceObject = parentWithInterfaceObject.parent 1.2376 + if parentWithInterfaceObject: 1.2377 + parentIfaceName = parentWithInterfaceObject.identifier.name 1.2378 + parentDesc = self.descriptor.getDescriptor(parentIfaceName) 1.2379 + if parentDesc.workers: 1.2380 + parentIfaceName += "_workers" 1.2381 + getConstructorProto = ("%s::GetConstructorObject(aCx, aGlobal)" % 1.2382 + toBindingNamespace(parentIfaceName)) 1.2383 + constructorProtoType = "Handle" 1.2384 + else: 1.2385 + getConstructorProto = "aCx, JS_GetFunctionPrototype(aCx, aGlobal)" 1.2386 + constructorProtoType = "Rooted" 1.2387 + 1.2388 + needInterfaceObject = self.descriptor.interface.hasInterfaceObject() 1.2389 + needInterfacePrototypeObject = self.descriptor.interface.hasInterfacePrototypeObject() 1.2390 + 1.2391 + # if we don't need to create anything, why are we generating this? 1.2392 + assert needInterfaceObject or needInterfacePrototypeObject 1.2393 + 1.2394 + idsToInit = [] 1.2395 + # There is no need to init any IDs in workers, because worker bindings 1.2396 + # don't have Xrays. 1.2397 + if not self.descriptor.workers: 1.2398 + for var in self.properties.arrayNames(): 1.2399 + props = getattr(self.properties, var) 1.2400 + # We only have non-chrome ids to init if we have no chrome ids. 1.2401 + if props.hasChromeOnly(): 1.2402 + idsToInit.append(props.variableName(True)) 1.2403 + if props.hasNonChromeOnly(): 1.2404 + idsToInit.append(props.variableName(False)) 1.2405 + if len(idsToInit) > 0: 1.2406 + initIdCalls = ["!InitIds(aCx, %s, %s_ids)" % (varname, varname) 1.2407 + for varname in idsToInit] 1.2408 + idsInitedFlag = CGGeneric("static bool sIdsInited = false;\n") 1.2409 + setFlag = CGGeneric("sIdsInited = true;\n") 1.2410 + initIdConditionals = [CGIfWrapper(CGGeneric("return;\n"), call) 1.2411 + for call in initIdCalls] 1.2412 + initIds = CGList([idsInitedFlag, 1.2413 + CGIfWrapper(CGList(initIdConditionals + [setFlag]), 1.2414 + "!sIdsInited && NS_IsMainThread()")]) 1.2415 + else: 1.2416 + initIds = None 1.2417 + 1.2418 + prefCacheData = [] 1.2419 + for var in self.properties.arrayNames(): 1.2420 + props = getattr(self.properties, var) 1.2421 + prefCacheData.extend(props.prefCacheData) 1.2422 + if len(prefCacheData) != 0: 1.2423 + prefCacheData = [ 1.2424 + CGGeneric('Preferences::AddBoolVarCache(%s, "%s");\n' % (ptr, pref)) 1.2425 + for pref, ptr in prefCacheData] 1.2426 + prefCache = CGWrapper(CGIndenter(CGList(prefCacheData)), 1.2427 + pre=("static bool sPrefCachesInited = false;\n" 1.2428 + "if (!sPrefCachesInited) {\n" 1.2429 + " sPrefCachesInited = true;\n"), 1.2430 + post="}\n") 1.2431 + else: 1.2432 + prefCache = None 1.2433 + 1.2434 + if UseHolderForUnforgeable(self.descriptor): 1.2435 + createUnforgeableHolder = CGGeneric(dedent(""" 1.2436 + JS::Rooted<JSObject*> unforgeableHolder(aCx, 1.2437 + JS_NewObjectWithGivenProto(aCx, nullptr, JS::NullPtr(), JS::NullPtr())); 1.2438 + if (!unforgeableHolder) { 1.2439 + return; 1.2440 + } 1.2441 + """)) 1.2442 + defineUnforgeables = InitUnforgeablePropertiesOnObject(self.descriptor, 1.2443 + "unforgeableHolder", 1.2444 + self.properties) 1.2445 + createUnforgeableHolder = CGList( 1.2446 + [createUnforgeableHolder, defineUnforgeables]) 1.2447 + else: 1.2448 + createUnforgeableHolder = None 1.2449 + 1.2450 + getParentProto = fill( 1.2451 + """ 1.2452 + JS::${type}<JSObject*> parentProto(${getParentProto}); 1.2453 + if (!parentProto) { 1.2454 + return; 1.2455 + } 1.2456 + """, 1.2457 + type=parentProtoType, 1.2458 + getParentProto=getParentProto) 1.2459 + 1.2460 + getConstructorProto = fill( 1.2461 + """ 1.2462 + JS::${type}<JSObject*> constructorProto(${getConstructorProto}); 1.2463 + if (!constructorProto) { 1.2464 + return; 1.2465 + } 1.2466 + """, 1.2467 + type=constructorProtoType, 1.2468 + getConstructorProto=getConstructorProto) 1.2469 + 1.2470 + if (needInterfaceObject and 1.2471 + self.descriptor.needsConstructHookHolder()): 1.2472 + constructHookHolder = "&" + CONSTRUCT_HOOK_NAME + "_holder" 1.2473 + else: 1.2474 + constructHookHolder = "nullptr" 1.2475 + if self.descriptor.interface.ctor(): 1.2476 + constructArgs = methodLength(self.descriptor.interface.ctor()) 1.2477 + else: 1.2478 + constructArgs = 0 1.2479 + if len(self.descriptor.interface.namedConstructors) > 0: 1.2480 + namedConstructors = "namedConstructors" 1.2481 + else: 1.2482 + namedConstructors = "nullptr" 1.2483 + 1.2484 + if needInterfacePrototypeObject: 1.2485 + protoClass = "&PrototypeClass.mBase" 1.2486 + protoCache = "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)" % self.descriptor.name 1.2487 + else: 1.2488 + protoClass = "nullptr" 1.2489 + protoCache = "nullptr" 1.2490 + if needInterfaceObject: 1.2491 + interfaceClass = "&InterfaceObjectClass.mBase" 1.2492 + interfaceCache = "&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)" % self.descriptor.name 1.2493 + else: 1.2494 + # We don't have slots to store the named constructors. 1.2495 + assert len(self.descriptor.interface.namedConstructors) == 0 1.2496 + interfaceClass = "nullptr" 1.2497 + interfaceCache = "nullptr" 1.2498 + 1.2499 + if self.descriptor.concrete: 1.2500 + domClass = "&Class.mClass" 1.2501 + else: 1.2502 + domClass = "nullptr" 1.2503 + 1.2504 + if self.properties.hasNonChromeOnly(): 1.2505 + properties = "&sNativeProperties" 1.2506 + else: 1.2507 + properties = "nullptr" 1.2508 + if self.properties.hasChromeOnly(): 1.2509 + accessCheck = "nsContentUtils::ThreadsafeIsCallerChrome()" 1.2510 + chromeProperties = accessCheck + " ? &sChromeOnlyNativeProperties : nullptr" 1.2511 + else: 1.2512 + chromeProperties = "nullptr" 1.2513 + 1.2514 + call = fill( 1.2515 + """ 1.2516 + dom::CreateInterfaceObjects(aCx, aGlobal, parentProto, 1.2517 + ${protoClass}, ${protoCache}, 1.2518 + constructorProto, ${interfaceClass}, ${constructHookHolder}, ${constructArgs}, ${namedConstructors}, 1.2519 + ${interfaceCache}, 1.2520 + ${domClass}, 1.2521 + ${properties}, 1.2522 + ${chromeProperties}, 1.2523 + ${name}, aDefineOnGlobal); 1.2524 + """, 1.2525 + protoClass=protoClass, 1.2526 + protoCache=protoCache, 1.2527 + interfaceClass=interfaceClass, 1.2528 + constructHookHolder=constructHookHolder, 1.2529 + constructArgs=constructArgs, 1.2530 + namedConstructors=namedConstructors, 1.2531 + interfaceCache=interfaceCache, 1.2532 + domClass=domClass, 1.2533 + properties=properties, 1.2534 + chromeProperties=chromeProperties, 1.2535 + name='"' + self.descriptor.interface.identifier.name + '"' if needInterfaceObject else "nullptr") 1.2536 + 1.2537 + if UseHolderForUnforgeable(self.descriptor): 1.2538 + assert needInterfacePrototypeObject 1.2539 + setUnforgeableHolder = CGGeneric(fill( 1.2540 + """ 1.2541 + JSObject* proto = aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::${name}); 1.2542 + if (proto) { 1.2543 + js::SetReservedSlot(proto, DOM_INTERFACE_PROTO_SLOTS_BASE, 1.2544 + JS::ObjectValue(*unforgeableHolder)); 1.2545 + } 1.2546 + """, 1.2547 + name=self.descriptor.name)) 1.2548 + else: 1.2549 + setUnforgeableHolder = None 1.2550 + functionBody = CGList( 1.2551 + [CGGeneric(getParentProto), CGGeneric(getConstructorProto), initIds, 1.2552 + prefCache, createUnforgeableHolder, CGGeneric(call), setUnforgeableHolder], 1.2553 + "\n") 1.2554 + return CGIndenter(functionBody).define() 1.2555 + 1.2556 + 1.2557 +class CGGetPerInterfaceObject(CGAbstractMethod): 1.2558 + """ 1.2559 + A method for getting a per-interface object (a prototype object or interface 1.2560 + constructor object). 1.2561 + """ 1.2562 + def __init__(self, descriptor, name, idPrefix="", extraArgs=[]): 1.2563 + args = [Argument('JSContext*', 'aCx'), 1.2564 + Argument('JS::Handle<JSObject*>', 'aGlobal')] + extraArgs 1.2565 + CGAbstractMethod.__init__(self, descriptor, name, 1.2566 + 'JS::Handle<JSObject*>', args) 1.2567 + self.id = idPrefix + "id::" + self.descriptor.name 1.2568 + 1.2569 + def definition_body(self): 1.2570 + # BOGUS extra blank line at the beginning of the code below 1.2571 + # BOGUS - should be a blank line between an if-block and following comment below 1.2572 + return indent(fill( 1.2573 + """ 1.2574 + 1.2575 + /* Make sure our global is sane. Hopefully we can remove this sometime */ 1.2576 + if (!(js::GetObjectClass(aGlobal)->flags & JSCLASS_DOM_GLOBAL)) { 1.2577 + return JS::NullPtr(); 1.2578 + } 1.2579 + /* Check to see whether the interface objects are already installed */ 1.2580 + ProtoAndIfaceCache& protoAndIfaceCache = *GetProtoAndIfaceCache(aGlobal); 1.2581 + if (!protoAndIfaceCache.EntrySlotIfExists(${id})) { 1.2582 + CreateInterfaceObjects(aCx, aGlobal, protoAndIfaceCache, aDefineOnGlobal); 1.2583 + } 1.2584 + 1.2585 + /* 1.2586 + * The object might _still_ be null, but that's OK. 1.2587 + * 1.2588 + * Calling fromMarkedLocation() is safe because protoAndIfaceCache is 1.2589 + * traced by TraceProtoAndIfaceCache() and its contents are never 1.2590 + * changed after they have been set. 1.2591 + */ 1.2592 + return JS::Handle<JSObject*>::fromMarkedLocation(protoAndIfaceCache.EntrySlotMustExist(${id}).address()); 1.2593 + """, 1.2594 + id=self.id)) 1.2595 + 1.2596 + 1.2597 +class CGGetProtoObjectMethod(CGGetPerInterfaceObject): 1.2598 + """ 1.2599 + A method for getting the interface prototype object. 1.2600 + """ 1.2601 + def __init__(self, descriptor): 1.2602 + CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject", 1.2603 + "prototypes::") 1.2604 + 1.2605 + def definition_body(self): 1.2606 + # BOGUS extra blank line at start of method 1.2607 + return indent(dedent(""" 1.2608 + 1.2609 + /* Get the interface prototype object for this class. This will create the 1.2610 + object as needed. */ 1.2611 + bool aDefineOnGlobal = true; 1.2612 + """)) + CGGetPerInterfaceObject.definition_body(self) 1.2613 + 1.2614 + 1.2615 +class CGGetConstructorObjectMethod(CGGetPerInterfaceObject): 1.2616 + """ 1.2617 + A method for getting the interface constructor object. 1.2618 + """ 1.2619 + def __init__(self, descriptor): 1.2620 + CGGetPerInterfaceObject.__init__( 1.2621 + self, descriptor, "GetConstructorObject", 1.2622 + "constructors::", 1.2623 + extraArgs=[Argument("bool", "aDefineOnGlobal", "true")]) 1.2624 + 1.2625 + def definition_body(self): 1.2626 + # BOGUS extra blank line at start of method 1.2627 + return indent(dedent(""" 1.2628 + 1.2629 + /* Get the interface object for this class. This will create the object as 1.2630 + needed. */ 1.2631 + """)) + CGGetPerInterfaceObject.definition_body(self) 1.2632 + 1.2633 + 1.2634 +class CGDefineDOMInterfaceMethod(CGAbstractMethod): 1.2635 + """ 1.2636 + A method for resolve hooks to try to lazily define the interface object for 1.2637 + a given interface. 1.2638 + """ 1.2639 + def __init__(self, descriptor): 1.2640 + args = [Argument('JSContext*', 'aCx'), 1.2641 + Argument('JS::Handle<JSObject*>', 'aGlobal'), 1.2642 + Argument('JS::Handle<jsid>', 'id'), 1.2643 + Argument('bool', 'aDefineOnGlobal')] 1.2644 + CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'JSObject*', args) 1.2645 + 1.2646 + def declare(self): 1.2647 + if self.descriptor.workers: 1.2648 + return '' 1.2649 + return CGAbstractMethod.declare(self) 1.2650 + 1.2651 + def define(self): 1.2652 + if self.descriptor.workers: 1.2653 + return '' 1.2654 + return CGAbstractMethod.define(self) 1.2655 + 1.2656 + def definition_body(self): 1.2657 + if len(self.descriptor.interface.namedConstructors) > 0: 1.2658 + getConstructor = indent(dedent(""" 1.2659 + JSObject* interfaceObject = GetConstructorObject(aCx, aGlobal, aDefineOnGlobal); 1.2660 + if (!interfaceObject) { 1.2661 + return nullptr; 1.2662 + } 1.2663 + for (unsigned slot = DOM_INTERFACE_SLOTS_BASE; slot < JSCLASS_RESERVED_SLOTS(&InterfaceObjectClass.mBase); ++slot) { 1.2664 + JSObject* constructor = &js::GetReservedSlot(interfaceObject, slot).toObject(); 1.2665 + if (JS_GetFunctionId(JS_GetObjectFunction(constructor)) == JSID_TO_STRING(id)) { 1.2666 + return constructor; 1.2667 + } 1.2668 + } 1.2669 + return interfaceObject; 1.2670 + """)) 1.2671 + else: 1.2672 + getConstructor = " return GetConstructorObject(aCx, aGlobal, aDefineOnGlobal);\n" 1.2673 + return getConstructor 1.2674 + 1.2675 + 1.2676 +class CGConstructorEnabled(CGAbstractMethod): 1.2677 + """ 1.2678 + A method for testing whether we should be exposing this interface 1.2679 + object or navigator property. This can perform various tests 1.2680 + depending on what conditions are specified on the interface. 1.2681 + """ 1.2682 + def __init__(self, descriptor): 1.2683 + CGAbstractMethod.__init__(self, descriptor, 1.2684 + 'ConstructorEnabled', 'bool', 1.2685 + [Argument("JSContext*", "aCx"), 1.2686 + Argument("JS::Handle<JSObject*>", "aObj")]) 1.2687 + 1.2688 + def definition_body(self): 1.2689 + conditions = [] 1.2690 + iface = self.descriptor.interface 1.2691 + pref = iface.getExtendedAttribute("Pref") 1.2692 + if pref: 1.2693 + assert isinstance(pref, list) and len(pref) == 1 1.2694 + conditions.append('Preferences::GetBool("%s")' % pref[0]) 1.2695 + if iface.getExtendedAttribute("ChromeOnly"): 1.2696 + conditions.append("nsContentUtils::ThreadsafeIsCallerChrome()") 1.2697 + func = iface.getExtendedAttribute("Func") 1.2698 + if func: 1.2699 + assert isinstance(func, list) and len(func) == 1 1.2700 + conditions.append("%s(aCx, aObj)" % func[0]) 1.2701 + availableIn = getAvailableInTestFunc(iface) 1.2702 + if availableIn: 1.2703 + conditions.append("%s(aCx, aObj)" % availableIn) 1.2704 + # We should really have some conditions 1.2705 + assert len(conditions) 1.2706 + body = CGWrapper(CGList((CGGeneric(cond) for cond in conditions), 1.2707 + " &&\n"), 1.2708 + pre="return ", post=";\n", reindent=True) 1.2709 + return CGIndenter(body).define() 1.2710 + 1.2711 + 1.2712 +def CreateBindingJSObject(descriptor, properties, parent): 1.2713 + # We don't always need to root obj, but there are a variety 1.2714 + # of cases where we do, so for simplicity, just always root it. 1.2715 + objDecl = "JS::Rooted<JSObject*> obj(aCx);\n" 1.2716 + if descriptor.proxy: 1.2717 + create = fill( 1.2718 + """ 1.2719 + JS::Rooted<JS::Value> proxyPrivateVal(aCx, JS::PrivateValue(aObject)); 1.2720 + js::ProxyOptions options; 1.2721 + options.setClass(&Class.mBase); 1.2722 + obj = NewProxyObject(aCx, DOMProxyHandler::getInstance(), 1.2723 + proxyPrivateVal, proto, ${parent}, options); 1.2724 + if (!obj) { 1.2725 + return nullptr; 1.2726 + } 1.2727 + 1.2728 + """, 1.2729 + parent=parent) 1.2730 + if descriptor.interface.getExtendedAttribute('OverrideBuiltins'): 1.2731 + create += dedent(""" 1.2732 + js::SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, 1.2733 + JS::PrivateValue(&aObject->mExpandoAndGeneration)); 1.2734 + 1.2735 + """) 1.2736 + else: 1.2737 + create = fill( 1.2738 + """ 1.2739 + obj = JS_NewObject(aCx, Class.ToJSClass(), proto, ${parent}); 1.2740 + if (!obj) { 1.2741 + return nullptr; 1.2742 + } 1.2743 + 1.2744 + js::SetReservedSlot(obj, DOM_OBJECT_SLOT, PRIVATE_TO_JSVAL(aObject)); 1.2745 + """, 1.2746 + parent=parent) 1.2747 + if "Window" in descriptor.interface.identifier.name: 1.2748 + create = dedent(""" 1.2749 + MOZ_ASSERT(false, 1.2750 + "Our current reserved slot situation is unsafe for globals. Fix " 1.2751 + "bug 760095!"); 1.2752 + """) + create 1.2753 + create = objDecl + create 1.2754 + 1.2755 + if descriptor.nativeOwnership == 'refcounted': 1.2756 + create += "NS_ADDREF(aObject);\n" 1.2757 + else: 1.2758 + create += dedent(""" 1.2759 + // Make sure the native objects inherit from NonRefcountedDOMObject so that we 1.2760 + // log their ctor and dtor. 1.2761 + MustInheritFromNonRefcountedDOMObject(aObject); 1.2762 + *aTookOwnership = true; 1.2763 + """) 1.2764 + return create 1.2765 + 1.2766 + 1.2767 +def InitUnforgeablePropertiesOnObject(descriptor, obj, properties, failureReturnValue=""): 1.2768 + """ 1.2769 + properties is a PropertyArrays instance 1.2770 + """ 1.2771 + defineUnforgeables = fill( 1.2772 + """ 1.2773 + if (!DefineUnforgeableAttributes(aCx, ${obj}, %s)) { 1.2774 + return${rv}; 1.2775 + } 1.2776 + """, 1.2777 + obj=obj, 1.2778 + rv=" " + failureReturnValue if failureReturnValue else "") 1.2779 + 1.2780 + unforgeableAttrs = properties.unforgeableAttrs 1.2781 + unforgeables = [] 1.2782 + if unforgeableAttrs.hasNonChromeOnly(): 1.2783 + unforgeables.append(CGGeneric(defineUnforgeables % 1.2784 + unforgeableAttrs.variableName(False))) 1.2785 + if unforgeableAttrs.hasChromeOnly(): 1.2786 + unforgeables.append( 1.2787 + CGIfWrapper(CGGeneric(defineUnforgeables % 1.2788 + unforgeableAttrs.variableName(True)), 1.2789 + "nsContentUtils::ThreadsafeIsCallerChrome()")) 1.2790 + return CGList(unforgeables) 1.2791 + 1.2792 + 1.2793 +def InitUnforgeableProperties(descriptor, properties): 1.2794 + """ 1.2795 + properties is a PropertyArrays instance 1.2796 + """ 1.2797 + unforgeableAttrs = properties.unforgeableAttrs 1.2798 + if not unforgeableAttrs.hasNonChromeOnly() and not unforgeableAttrs.hasChromeOnly(): 1.2799 + return "" 1.2800 + 1.2801 + if descriptor.proxy: 1.2802 + unforgeableProperties = CGGeneric( 1.2803 + "// Unforgeable properties on proxy-based bindings are stored in an object held\n" 1.2804 + "// by the interface prototype object.\n" 1.2805 + "\n") # BOGUS extra blank line 1.2806 + else: 1.2807 + unforgeableProperties = CGWrapper( 1.2808 + InitUnforgeablePropertiesOnObject(descriptor, "obj", properties, "nullptr"), 1.2809 + pre=( 1.2810 + "// Important: do unforgeable property setup after we have handed\n" 1.2811 + "// over ownership of the C++ object to obj as needed, so that if\n" 1.2812 + "// we fail and it ends up GCed it won't have problems in the\n" 1.2813 + "// finalizer trying to drop its ownership of the C++ object.\n")) 1.2814 + return CGWrapper(unforgeableProperties, pre="\n").define() 1.2815 + 1.2816 + 1.2817 +def AssertInheritanceChain(descriptor): 1.2818 + asserts = "" 1.2819 + iface = descriptor.interface 1.2820 + while iface: 1.2821 + desc = descriptor.getDescriptor(iface.identifier.name) 1.2822 + asserts += ( 1.2823 + " MOZ_ASSERT(static_cast<%s*>(aObject) == \n" 1.2824 + " reinterpret_cast<%s*>(aObject));\n" % 1.2825 + (desc.nativeType, desc.nativeType)) 1.2826 + iface = iface.parent 1.2827 + asserts += " MOZ_ASSERT(ToSupportsIsCorrect(aObject));\n" 1.2828 + return asserts 1.2829 + 1.2830 + 1.2831 +def InitMemberSlots(descriptor, wrapperCache): 1.2832 + """ 1.2833 + Initialize member slots on our JS object if we're supposed to have some. 1.2834 + 1.2835 + Note that this is called after the SetWrapper() call in the 1.2836 + wrapperCache case, since that can affect how our getters behave 1.2837 + and we plan to invoke them here. So if we fail, we need to 1.2838 + ClearWrapper. 1.2839 + """ 1.2840 + if not descriptor.interface.hasMembersInSlots(): 1.2841 + return "\n" # BOGUS blank line only if this returns empty 1.2842 + if wrapperCache: 1.2843 + clearWrapper = " aCache->ClearWrapper();\n" 1.2844 + else: 1.2845 + clearWrapper = "" 1.2846 + return ("if (!UpdateMemberSlots(aCx, obj, aObject)) {\n" 1.2847 + "%s" 1.2848 + " return nullptr;\n" 1.2849 + "}\n" % clearWrapper) 1.2850 + 1.2851 + 1.2852 +class CGWrapWithCacheMethod(CGAbstractMethod): 1.2853 + """ 1.2854 + Create a wrapper JSObject for a given native that implements nsWrapperCache. 1.2855 + 1.2856 + properties should be a PropertyArrays instance. 1.2857 + """ 1.2858 + def __init__(self, descriptor, properties): 1.2859 + assert descriptor.interface.hasInterfacePrototypeObject() 1.2860 + args = [Argument('JSContext*', 'aCx'), 1.2861 + Argument(descriptor.nativeType + '*', 'aObject'), 1.2862 + Argument('nsWrapperCache*', 'aCache')] 1.2863 + CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args) 1.2864 + self.properties = properties 1.2865 + 1.2866 + def definition_body(self): 1.2867 + return fill( 1.2868 + """ 1.2869 + ${assertion} 1.2870 + MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), 1.2871 + "nsISupports must be on our primary inheritance chain"); 1.2872 + 1.2873 + JS::Rooted<JSObject*> parent(aCx, 1.2874 + GetRealParentObject(aObject, 1.2875 + WrapNativeParent(aCx, aObject->GetParentObject()))); 1.2876 + if (!parent) { 1.2877 + return nullptr; 1.2878 + } 1.2879 + 1.2880 + // That might have ended up wrapping us already, due to the wonders 1.2881 + // of XBL. Check for that, and bail out as needed. Scope so we don't 1.2882 + // collide with the "obj" we declare in CreateBindingJSObject. 1.2883 + { 1.2884 + JSObject* obj = aCache->GetWrapper(); 1.2885 + if (obj) { 1.2886 + return obj; 1.2887 + } 1.2888 + } 1.2889 + 1.2890 + JSAutoCompartment ac(aCx, parent); 1.2891 + JS::Rooted<JSObject*> global(aCx, JS_GetGlobalForObject(aCx, parent)); 1.2892 + JS::Handle<JSObject*> proto = GetProtoObject(aCx, global); 1.2893 + if (!proto) { 1.2894 + return nullptr; 1.2895 + } 1.2896 + 1.2897 + $*{parent} 1.2898 + 1.2899 + $*{unforgeable} 1.2900 + 1.2901 + aCache->SetWrapper(obj); 1.2902 + $*{slots} 1.2903 + return obj; 1.2904 + """, 1.2905 + assertion=AssertInheritanceChain(self.descriptor), 1.2906 + parent=CreateBindingJSObject(self.descriptor, self.properties, 1.2907 + "parent"), 1.2908 + unforgeable=InitUnforgeableProperties(self.descriptor, self.properties), 1.2909 + slots=InitMemberSlots(self.descriptor, True)) 1.2910 + 1.2911 + 1.2912 +class CGWrapMethod(CGAbstractMethod): 1.2913 + def __init__(self, descriptor): 1.2914 + # XXX can we wrap if we don't have an interface prototype object? 1.2915 + assert descriptor.interface.hasInterfacePrototypeObject() 1.2916 + args = [Argument('JSContext*', 'aCx'), 1.2917 + Argument('T*', 'aObject')] 1.2918 + CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args, 1.2919 + inline=True, templateArgs=["class T"]) 1.2920 + 1.2921 + def definition_body(self): 1.2922 + return " return Wrap(aCx, aObject, aObject);\n" 1.2923 + 1.2924 + 1.2925 +class CGWrapNonWrapperCacheMethod(CGAbstractMethod): 1.2926 + """ 1.2927 + Create a wrapper JSObject for a given native that does not implement 1.2928 + nsWrapperCache. 1.2929 + 1.2930 + properties should be a PropertyArrays instance. 1.2931 + """ 1.2932 + def __init__(self, descriptor, properties): 1.2933 + # XXX can we wrap if we don't have an interface prototype object? 1.2934 + assert descriptor.interface.hasInterfacePrototypeObject() 1.2935 + args = [Argument('JSContext*', 'aCx'), 1.2936 + Argument(descriptor.nativeType + '*', 'aObject')] 1.2937 + if descriptor.nativeOwnership == 'owned': 1.2938 + args.append(Argument('bool*', 'aTookOwnership')) 1.2939 + CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args) 1.2940 + self.properties = properties 1.2941 + 1.2942 + def definition_body(self): 1.2943 + return fill( 1.2944 + """ 1.2945 + ${assertions} 1.2946 + JS::Rooted<JSObject*> global(aCx, JS::CurrentGlobalOrNull(aCx)); 1.2947 + JS::Handle<JSObject*> proto = GetProtoObject(aCx, global); 1.2948 + if (!proto) { 1.2949 + return nullptr; 1.2950 + } 1.2951 + 1.2952 + $*{global_} 1.2953 + 1.2954 + $*{unforgeable} 1.2955 + 1.2956 + $*{slots} 1.2957 + return obj; 1.2958 + """, 1.2959 + assertions=AssertInheritanceChain(self.descriptor), 1.2960 + global_=CreateBindingJSObject(self.descriptor, self.properties, 1.2961 + "global"), 1.2962 + unforgeable=InitUnforgeableProperties(self.descriptor, self.properties), 1.2963 + slots=InitMemberSlots(self.descriptor, False)) 1.2964 + 1.2965 + 1.2966 +class CGWrapGlobalMethod(CGAbstractMethod): 1.2967 + """ 1.2968 + Create a wrapper JSObject for a global. The global must implement 1.2969 + nsWrapperCache. 1.2970 + 1.2971 + properties should be a PropertyArrays instance. 1.2972 + """ 1.2973 + def __init__(self, descriptor, properties): 1.2974 + assert descriptor.interface.hasInterfacePrototypeObject() 1.2975 + args = [Argument('JSContext*', 'aCx'), 1.2976 + Argument(descriptor.nativeType + '*', 'aObject'), 1.2977 + Argument('nsWrapperCache*', 'aCache'), 1.2978 + Argument('JS::CompartmentOptions&', 'aOptions'), 1.2979 + Argument('JSPrincipals*', 'aPrincipal')] 1.2980 + CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args) 1.2981 + self.descriptor = descriptor 1.2982 + self.properties = properties 1.2983 + 1.2984 + def definition_body(self): 1.2985 + return fill( 1.2986 + """ 1.2987 + ${assertions} 1.2988 + MOZ_ASSERT(ToSupportsIsOnPrimaryInheritanceChain(aObject, aCache), 1.2989 + "nsISupports must be on our primary inheritance chain"); 1.2990 + 1.2991 + JS::Rooted<JSObject*> obj(aCx); 1.2992 + obj = CreateGlobal<${nativeType}, GetProtoObject>(aCx, 1.2993 + aObject, 1.2994 + aCache, 1.2995 + Class.ToJSClass(), 1.2996 + aOptions, 1.2997 + aPrincipal); 1.2998 + 1.2999 + $*{unforgeable} 1.3000 + 1.3001 + $*{slots} 1.3002 + 1.3003 + // XXXkhuey can't do this yet until workers can lazy resolve. 1.3004 + // JS_FireOnNewGlobalObject(aCx, obj); 1.3005 + 1.3006 + return obj; 1.3007 + """, 1.3008 + assertions=AssertInheritanceChain(self.descriptor), 1.3009 + nativeType=self.descriptor.nativeType, 1.3010 + unforgeable=InitUnforgeableProperties(self.descriptor, self.properties), 1.3011 + slots=InitMemberSlots(self.descriptor, True)) 1.3012 + 1.3013 + 1.3014 +class CGUpdateMemberSlotsMethod(CGAbstractStaticMethod): 1.3015 + def __init__(self, descriptor): 1.3016 + args = [Argument('JSContext*', 'aCx'), 1.3017 + Argument('JS::Handle<JSObject*>', 'aWrapper'), 1.3018 + Argument(descriptor.nativeType + '*', 'aObject')] 1.3019 + CGAbstractStaticMethod.__init__(self, descriptor, 'UpdateMemberSlots', 'bool', args) 1.3020 + 1.3021 + def definition_body(self): 1.3022 + body = ("JS::Rooted<JS::Value> temp(aCx);\n" 1.3023 + "JSJitGetterCallArgs args(&temp);\n") 1.3024 + for m in self.descriptor.interface.members: 1.3025 + if m.isAttr() and m.getExtendedAttribute("StoreInSlot"): 1.3026 + body += fill( 1.3027 + """ 1.3028 + 1.3029 + static_assert(${slot} < js::shadow::Object::MAX_FIXED_SLOTS, 1.3030 + "Not enough fixed slots to fit '${interface}.${member}'"); 1.3031 + if (!get_${member}(aCx, aWrapper, aObject, args)) { 1.3032 + return false; 1.3033 + } 1.3034 + // Getter handled setting our reserved slots 1.3035 + """, 1.3036 + slot=memberReservedSlot(m), 1.3037 + interface=self.descriptor.interface.identifier.name, 1.3038 + member=m.identifier.name) 1.3039 + 1.3040 + body += "\nreturn true;\n" 1.3041 + return indent(body) 1.3042 + 1.3043 + 1.3044 +class CGClearCachedValueMethod(CGAbstractMethod): 1.3045 + def __init__(self, descriptor, member): 1.3046 + self.member = member 1.3047 + # If we're StoreInSlot, we'll need to call the getter 1.3048 + if member.getExtendedAttribute("StoreInSlot"): 1.3049 + args = [Argument('JSContext*', 'aCx')] 1.3050 + returnType = 'bool' 1.3051 + else: 1.3052 + args = [] 1.3053 + returnType = 'void' 1.3054 + args.append(Argument(descriptor.nativeType + '*', 'aObject')) 1.3055 + name = ("ClearCached%sValue" % MakeNativeName(member.identifier.name)) 1.3056 + CGAbstractMethod.__init__(self, descriptor, name, returnType, args) 1.3057 + 1.3058 + def definition_body(self): 1.3059 + slotIndex = memberReservedSlot(self.member) 1.3060 + if self.member.getExtendedAttribute("StoreInSlot"): 1.3061 + # We have to root things and save the old value in case 1.3062 + # regetting fails, so we can restore it. 1.3063 + declObj = "JS::Rooted<JSObject*> obj(aCx);\n" 1.3064 + noopRetval = " true" 1.3065 + saveMember = ( 1.3066 + "JS::Rooted<JS::Value> oldValue(aCx, js::GetReservedSlot(obj, %s));\n" % 1.3067 + slotIndex) 1.3068 + regetMember = fill( 1.3069 + """ 1.3070 + JS::Rooted<JS::Value> temp(aCx); 1.3071 + JSJitGetterCallArgs args(&temp); 1.3072 + JSAutoCompartment ac(aCx, obj); 1.3073 + if (!get_${name}(aCx, obj, aObject, args)) { 1.3074 + js::SetReservedSlot(obj, ${slotIndex}, oldValue); 1.3075 + nsJSUtils::ReportPendingException(aCx); 1.3076 + return false; 1.3077 + } 1.3078 + return true; 1.3079 + """, 1.3080 + name=self.member.identifier.name, 1.3081 + slotIndex=slotIndex) 1.3082 + else: 1.3083 + declObj = "JSObject* obj;\n" 1.3084 + noopRetval = "" 1.3085 + saveMember = "" 1.3086 + regetMember = "" 1.3087 + 1.3088 + return indent(fill( 1.3089 + """ 1.3090 + $*{declObj} 1.3091 + obj = aObject->GetWrapper(); 1.3092 + if (!obj) { 1.3093 + return${noopRetval}; 1.3094 + } 1.3095 + $*{saveMember} 1.3096 + js::SetReservedSlot(obj, ${slotIndex}, JS::UndefinedValue()); 1.3097 + $*{regetMember} 1.3098 + """, 1.3099 + declObj=declObj, 1.3100 + noopRetval=noopRetval, 1.3101 + saveMember=saveMember, 1.3102 + slotIndex=slotIndex, 1.3103 + regetMember=regetMember)) 1.3104 + 1.3105 + 1.3106 +class CGIsPermittedMethod(CGAbstractMethod): 1.3107 + """ 1.3108 + crossOriginGetters/Setters/Methods are sets of names of the relevant members. 1.3109 + """ 1.3110 + def __init__(self, descriptor, crossOriginGetters, crossOriginSetters, 1.3111 + crossOriginMethods): 1.3112 + self.crossOriginGetters = crossOriginGetters 1.3113 + self.crossOriginSetters = crossOriginSetters 1.3114 + self.crossOriginMethods = crossOriginMethods 1.3115 + args = [Argument("JSFlatString*", "prop"), 1.3116 + Argument("jschar", "propFirstChar"), 1.3117 + Argument("bool", "set")] 1.3118 + CGAbstractMethod.__init__(self, descriptor, "IsPermitted", "bool", args, 1.3119 + inline=True) 1.3120 + 1.3121 + def definition_body(self): 1.3122 + allNames = self.crossOriginGetters | self.crossOriginSetters | self.crossOriginMethods 1.3123 + readwrite = self.crossOriginGetters & self.crossOriginSetters 1.3124 + readonly = (self.crossOriginGetters - self.crossOriginSetters) | self.crossOriginMethods 1.3125 + writeonly = self.crossOriginSetters - self.crossOriginGetters 1.3126 + cases = {} 1.3127 + for name in sorted(allNames): 1.3128 + cond = 'JS_FlatStringEqualsAscii(prop, "%s")' % name 1.3129 + if name in readonly: 1.3130 + cond = "!set && %s" % cond 1.3131 + elif name in writeonly: 1.3132 + cond = "set && %s" % cond 1.3133 + else: 1.3134 + assert name in readwrite 1.3135 + firstLetter = name[0] 1.3136 + case = cases.get(firstLetter, CGList([])) 1.3137 + case.append(CGGeneric("if (%s) {\n" 1.3138 + " return true;\n" 1.3139 + "}\n" % cond)) 1.3140 + cases[firstLetter] = case 1.3141 + caseList = [] 1.3142 + for firstLetter in sorted(cases.keys()): 1.3143 + caseList.append(CGCase("'%s'" % firstLetter, cases[firstLetter])) 1.3144 + switch = CGSwitch("propFirstChar", caseList) 1.3145 + return indent(switch.define() + "\nreturn false;\n") 1.3146 + 1.3147 +builtinNames = { 1.3148 + IDLType.Tags.bool: 'bool', 1.3149 + IDLType.Tags.int8: 'int8_t', 1.3150 + IDLType.Tags.int16: 'int16_t', 1.3151 + IDLType.Tags.int32: 'int32_t', 1.3152 + IDLType.Tags.int64: 'int64_t', 1.3153 + IDLType.Tags.uint8: 'uint8_t', 1.3154 + IDLType.Tags.uint16: 'uint16_t', 1.3155 + IDLType.Tags.uint32: 'uint32_t', 1.3156 + IDLType.Tags.uint64: 'uint64_t', 1.3157 + IDLType.Tags.unrestricted_float: 'float', 1.3158 + IDLType.Tags.float: 'float', 1.3159 + IDLType.Tags.unrestricted_double: 'double', 1.3160 + IDLType.Tags.double: 'double' 1.3161 +} 1.3162 + 1.3163 +numericSuffixes = { 1.3164 + IDLType.Tags.int8: '', 1.3165 + IDLType.Tags.uint8: '', 1.3166 + IDLType.Tags.int16: '', 1.3167 + IDLType.Tags.uint16: '', 1.3168 + IDLType.Tags.int32: '', 1.3169 + IDLType.Tags.uint32: 'U', 1.3170 + IDLType.Tags.int64: 'LL', 1.3171 + IDLType.Tags.uint64: 'ULL', 1.3172 + IDLType.Tags.unrestricted_float: 'F', 1.3173 + IDLType.Tags.float: 'F', 1.3174 + IDLType.Tags.unrestricted_double: '', 1.3175 + IDLType.Tags.double: '' 1.3176 +} 1.3177 + 1.3178 + 1.3179 +def numericValue(t, v): 1.3180 + if (t == IDLType.Tags.unrestricted_double or 1.3181 + t == IDLType.Tags.unrestricted_float): 1.3182 + typeName = builtinNames[t] 1.3183 + if v == float("inf"): 1.3184 + return "mozilla::PositiveInfinity<%s>()" % typeName 1.3185 + if v == float("-inf"): 1.3186 + return "mozilla::NegativeInfinity<%s>()" % typeName 1.3187 + if math.isnan(v): 1.3188 + return "mozilla::UnspecifiedNaN<%s>()" % typeName 1.3189 + return "%s%s" % (v, numericSuffixes[t]) 1.3190 + 1.3191 + 1.3192 +class CastableObjectUnwrapper(): 1.3193 + """ 1.3194 + A class for unwrapping an object named by the "source" argument 1.3195 + based on the passed-in descriptor and storing it in a variable 1.3196 + called by the name in the "target" argument. 1.3197 + 1.3198 + codeOnFailure is the code to run if unwrapping fails. 1.3199 + 1.3200 + If isCallbackReturnValue is "JSImpl" and our descriptor is also 1.3201 + JS-implemented, fall back to just creating the right object if what we 1.3202 + have isn't one already. 1.3203 + 1.3204 + If allowCrossOriginObj is True, then we'll first do an 1.3205 + UncheckedUnwrap and then operate on the result. 1.3206 + """ 1.3207 + def __init__(self, descriptor, source, target, codeOnFailure, 1.3208 + exceptionCode=None, isCallbackReturnValue=False, 1.3209 + allowCrossOriginObj=False): 1.3210 + self.substitution = { 1.3211 + "type": descriptor.nativeType, 1.3212 + "protoID": "prototypes::id::" + descriptor.name, 1.3213 + "target": target, 1.3214 + "codeOnFailure": codeOnFailure, 1.3215 + } 1.3216 + if allowCrossOriginObj: 1.3217 + self.substitution["uncheckedObjDecl"] = ( 1.3218 + "JS::Rooted<JSObject*> uncheckedObj(cx, js::UncheckedUnwrap(%s));\n" % source) 1.3219 + self.substitution["source"] = "uncheckedObj" 1.3220 + xpconnectUnwrap = dedent(""" 1.3221 + nsresult rv; 1.3222 + { // Scope for the JSAutoCompartment, because we only 1.3223 + // want to be in that compartment for the UnwrapArg call. 1.3224 + JSAutoCompartment ac(cx, ${source}); 1.3225 + rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val); 1.3226 + } 1.3227 + """) 1.3228 + else: 1.3229 + self.substitution["uncheckedObjDecl"] = "" 1.3230 + self.substitution["source"] = source 1.3231 + xpconnectUnwrap = "nsresult rv = UnwrapArg<${type}>(cx, val, &objPtr, &objRef.ptr, &val);\n" 1.3232 + 1.3233 + if descriptor.hasXPConnectImpls: 1.3234 + # We don't use xpc_qsUnwrapThis because it will always throw on 1.3235 + # unwrap failure, whereas we want to control whether we throw or 1.3236 + # not. 1.3237 + self.substitution["codeOnFailure"] = string.Template( 1.3238 + "${type} *objPtr;\n" 1.3239 + "SelfRef objRef;\n" 1.3240 + "JS::Rooted<JS::Value> val(cx, JS::ObjectValue(*${source}));\n" + 1.3241 + xpconnectUnwrap + 1.3242 + "if (NS_FAILED(rv)) {\n" 1.3243 + "${indentedCodeOnFailure}" 1.3244 + "}\n" 1.3245 + "// We should be castable!\n" 1.3246 + "MOZ_ASSERT(!objRef.ptr);\n" 1.3247 + "// We should have an object, too!\n" 1.3248 + "MOZ_ASSERT(objPtr);\n" 1.3249 + "${target} = objPtr;\n" 1.3250 + ).substitute(self.substitution, 1.3251 + indentedCodeOnFailure=indent(codeOnFailure)) 1.3252 + elif (isCallbackReturnValue == "JSImpl" and 1.3253 + descriptor.interface.isJSImplemented()): 1.3254 + exceptionCode = exceptionCode or codeOnFailure 1.3255 + self.substitution["codeOnFailure"] = fill( 1.3256 + """ 1.3257 + // Be careful to not wrap random DOM objects here, even if 1.3258 + // they're wrapped in opaque security wrappers for some reason. 1.3259 + // XXXbz Wish we could check for a JS-implemented object 1.3260 + // that already has a content reflection... 1.3261 + if (!IsDOMObject(js::UncheckedUnwrap(${source}))) { 1.3262 + nsCOMPtr<nsPIDOMWindow> ourWindow; 1.3263 + if (!GetWindowForJSImplementedObject(cx, Callback(), getter_AddRefs(ourWindow))) { 1.3264 + $*{exceptionCode} 1.3265 + } 1.3266 + JS::Rooted<JSObject*> jsImplSourceObj(cx, ${source}); 1.3267 + ${target} = new ${type}(jsImplSourceObj, ourWindow); 1.3268 + } else { 1.3269 + $*{codeOnFailure} 1.3270 + } 1.3271 + """, 1.3272 + exceptionCode=exceptionCode, 1.3273 + **self.substitution) 1.3274 + else: 1.3275 + self.substitution["codeOnFailure"] = codeOnFailure 1.3276 + 1.3277 + def __str__(self): 1.3278 + substitution = self.substitution.copy() 1.3279 + substitution["codeOnFailure"] %= { 1.3280 + 'securityError': 'rv == NS_ERROR_XPC_SECURITY_MANAGER_VETO' 1.3281 + } 1.3282 + return fill( 1.3283 + """ 1.3284 + { 1.3285 + $*{uncheckedObjDecl} 1.3286 + nsresult rv = UnwrapObject<${protoID}, ${type}>(${source}, ${target}); 1.3287 + if (NS_FAILED(rv)) { 1.3288 + $*{codeOnFailure} 1.3289 + } 1.3290 + } 1.3291 + """, 1.3292 + **substitution) 1.3293 + 1.3294 + 1.3295 +class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper): 1.3296 + """ 1.3297 + As CastableObjectUnwrapper, but defaulting to throwing if unwrapping fails 1.3298 + """ 1.3299 + def __init__(self, descriptor, source, target, exceptionCode, 1.3300 + isCallbackReturnValue, sourceDescription): 1.3301 + CastableObjectUnwrapper.__init__( 1.3302 + self, descriptor, source, target, 1.3303 + 'ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n' 1.3304 + '%s' % (sourceDescription, descriptor.interface.identifier.name, 1.3305 + exceptionCode), 1.3306 + exceptionCode, 1.3307 + isCallbackReturnValue) 1.3308 + 1.3309 + 1.3310 +class CGCallbackTempRoot(CGGeneric): 1.3311 + def __init__(self, name): 1.3312 + define = dedent(""" 1.3313 + { // Scope for tempRoot 1.3314 + JS::Rooted<JSObject*> tempRoot(cx, &${val}.toObject()); 1.3315 + ${declName} = new %s(tempRoot, mozilla::dom::GetIncumbentGlobal()); 1.3316 + } 1.3317 + """) % name 1.3318 + CGGeneric.__init__(self, define=define) 1.3319 + 1.3320 + 1.3321 +class JSToNativeConversionInfo(): 1.3322 + """ 1.3323 + An object representing information about a JS-to-native conversion. 1.3324 + """ 1.3325 + def __init__(self, template, declType=None, holderType=None, 1.3326 + dealWithOptional=False, declArgs=None, 1.3327 + holderArgs=None): 1.3328 + """ 1.3329 + template: A string representing the conversion code. This will have 1.3330 + template substitution performed on it as follows: 1.3331 + 1.3332 + ${val} is a handle to the JS::Value in question 1.3333 + ${mutableVal} is a mutable handle to the JS::Value in question 1.3334 + ${holderName} replaced by the holder's name, if any 1.3335 + ${declName} replaced by the declaration's name 1.3336 + ${haveValue} replaced by an expression that evaluates to a boolean 1.3337 + for whether we have a JS::Value. Only used when 1.3338 + defaultValue is not None or when True is passed for 1.3339 + checkForValue to instantiateJSToNativeConversion. 1.3340 + 1.3341 + declType: A CGThing representing the native C++ type we're converting 1.3342 + to. This is allowed to be None if the conversion code is 1.3343 + supposed to be used as-is. 1.3344 + 1.3345 + holderType: A CGThing representing the type of a "holder" which will 1.3346 + hold a possible reference to the C++ thing whose type we 1.3347 + returned in declType, or None if no such holder is needed. 1.3348 + 1.3349 + dealWithOptional: A boolean indicating whether the caller has to do 1.3350 + optional-argument handling. This should only be set 1.3351 + to true if the JS-to-native conversion is being done 1.3352 + for an optional argument or dictionary member with no 1.3353 + default value and if the returned template expects 1.3354 + both declType and holderType to be wrapped in 1.3355 + Optional<>, with ${declName} and ${holderName} 1.3356 + adjusted to point to the Value() of the Optional, and 1.3357 + Construct() calls to be made on the Optional<>s as 1.3358 + needed. 1.3359 + 1.3360 + declArgs: If not None, the arguments to pass to the ${declName} 1.3361 + constructor. These will have template substitution performed 1.3362 + on them so you can use things like ${val}. This is a 1.3363 + single string, not a list of strings. 1.3364 + 1.3365 + holderArgs: If not None, the arguments to pass to the ${holderName} 1.3366 + constructor. These will have template substitution 1.3367 + performed on them so you can use things like ${val}. 1.3368 + This is a single string, not a list of strings. 1.3369 + 1.3370 + ${declName} must be in scope before the code from 'template' is entered. 1.3371 + 1.3372 + If holderType is not None then ${holderName} must be in scope before 1.3373 + the code from 'template' is entered. 1.3374 + """ 1.3375 + assert isinstance(template, str) 1.3376 + assert declType is None or isinstance(declType, CGThing) 1.3377 + assert holderType is None or isinstance(holderType, CGThing) 1.3378 + self.template = template 1.3379 + self.declType = declType 1.3380 + self.holderType = holderType 1.3381 + self.dealWithOptional = dealWithOptional 1.3382 + self.declArgs = declArgs 1.3383 + self.holderArgs = holderArgs 1.3384 + 1.3385 + 1.3386 +def getHandleDefault(defaultValue): 1.3387 + tag = defaultValue.type.tag() 1.3388 + if tag in numericSuffixes: 1.3389 + # Some numeric literals require a suffix to compile without warnings 1.3390 + return numericValue(tag, defaultValue.value) 1.3391 + assert tag == IDLType.Tags.bool 1.3392 + return toStringBool(defaultValue.value) 1.3393 + 1.3394 + 1.3395 +def handleDefaultStringValue(defaultValue, method): 1.3396 + """ 1.3397 + Returns a string which ends up calling 'method' with a (char16_t*, length) 1.3398 + pair that sets this string default value. This string is suitable for 1.3399 + passing as the second argument of handleDefault; in particular it does not 1.3400 + end with a ';' 1.3401 + """ 1.3402 + assert defaultValue.type.isDOMString() 1.3403 + return ("static const char16_t data[] = { %s };\n" 1.3404 + "%s(data, ArrayLength(data) - 1)" % 1.3405 + (", ".join(["'" + char + "'" for char in 1.3406 + defaultValue.value] + ["0"]), 1.3407 + method)) 1.3408 + 1.3409 + 1.3410 +# If this function is modified, modify CGNativeMember.getArg and 1.3411 +# CGNativeMember.getRetvalInfo accordingly. The latter cares about the decltype 1.3412 +# and holdertype we end up using, because it needs to be able to return the code 1.3413 +# that will convert those to the actual return value of the callback function. 1.3414 +def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None, 1.3415 + isDefinitelyObject=False, 1.3416 + isMember=False, 1.3417 + isOptional=False, 1.3418 + invalidEnumValueFatal=True, 1.3419 + defaultValue=None, 1.3420 + treatNullAs="Default", 1.3421 + isEnforceRange=False, 1.3422 + isClamp=False, 1.3423 + isNullOrUndefined=False, 1.3424 + exceptionCode=None, 1.3425 + lenientFloatCode=None, 1.3426 + allowTreatNonCallableAsNull=False, 1.3427 + isCallbackReturnValue=False, 1.3428 + sourceDescription="value"): 1.3429 + """ 1.3430 + Get a template for converting a JS value to a native object based on the 1.3431 + given type and descriptor. If failureCode is given, then we're actually 1.3432 + testing whether we can convert the argument to the desired type. That 1.3433 + means that failures to convert due to the JS value being the wrong type of 1.3434 + value need to use failureCode instead of throwing exceptions. Failures to 1.3435 + convert that are due to JS exceptions (from toString or valueOf methods) or 1.3436 + out of memory conditions need to throw exceptions no matter what 1.3437 + failureCode is. However what actually happens when throwing an exception 1.3438 + can be controlled by exceptionCode. The only requirement on that is that 1.3439 + exceptionCode must end up doing a return, and every return from this 1.3440 + function must happen via exceptionCode if exceptionCode is not None. 1.3441 + 1.3442 + If isDefinitelyObject is True, that means we know the value 1.3443 + isObject() and we have no need to recheck that. 1.3444 + 1.3445 + if isMember is not False, we're being converted from a property of some JS 1.3446 + object, not from an actual method argument, so we can't rely on our jsval 1.3447 + being rooted or outliving us in any way. Callers can pass "Dictionary", 1.3448 + "Variadic", "Sequence", or "OwningUnion" to indicate that the conversion is 1.3449 + for something that is a dictionary member, a variadic argument, a sequence, 1.3450 + or an owning union respectively. 1.3451 + 1.3452 + If isOptional is true, then we are doing conversion of an optional 1.3453 + argument with no default value. 1.3454 + 1.3455 + invalidEnumValueFatal controls whether an invalid enum value conversion 1.3456 + attempt will throw (if true) or simply return without doing anything (if 1.3457 + false). 1.3458 + 1.3459 + If defaultValue is not None, it's the IDL default value for this conversion 1.3460 + 1.3461 + If isEnforceRange is true, we're converting an integer and throwing if the 1.3462 + value is out of range. 1.3463 + 1.3464 + If isClamp is true, we're converting an integer and clamping if the 1.3465 + value is out of range. 1.3466 + 1.3467 + If lenientFloatCode is not None, it should be used in cases when 1.3468 + we're a non-finite float that's not unrestricted. 1.3469 + 1.3470 + If allowTreatNonCallableAsNull is true, then [TreatNonCallableAsNull] and 1.3471 + [TreatNonObjectAsNull] extended attributes on nullable callback functions 1.3472 + will be honored. 1.3473 + 1.3474 + If isCallbackReturnValue is "JSImpl" or "Callback", then the declType may be 1.3475 + adjusted to make it easier to return from a callback. Since that type is 1.3476 + never directly observable by any consumers of the callback code, this is OK. 1.3477 + Furthermore, if isCallbackReturnValue is "JSImpl", that affects the behavior 1.3478 + of the FailureFatalCastableObjectUnwrapper conversion; this is used for 1.3479 + implementing auto-wrapping of JS-implemented return values from a 1.3480 + JS-implemented interface. 1.3481 + 1.3482 + sourceDescription is a description of what this JS value represents, to be 1.3483 + used in error reporting. Callers should assume that it might get placed in 1.3484 + the middle of a sentence. If it ends up at the beginning of a sentence, its 1.3485 + first character will be automatically uppercased. 1.3486 + 1.3487 + The return value from this function is a JSToNativeConversionInfo. 1.3488 + """ 1.3489 + # If we have a defaultValue then we're not actually optional for 1.3490 + # purposes of what we need to be declared as. 1.3491 + assert defaultValue is None or not isOptional 1.3492 + 1.3493 + # Also, we should not have a defaultValue if we know we're an object 1.3494 + assert not isDefinitelyObject or defaultValue is None 1.3495 + 1.3496 + # And we can't both be an object and be null or undefined 1.3497 + assert not isDefinitelyObject or not isNullOrUndefined 1.3498 + 1.3499 + # If exceptionCode is not set, we'll just rethrow the exception we got. 1.3500 + # Note that we can't just set failureCode to exceptionCode, because setting 1.3501 + # failureCode will prevent pending exceptions from being set in cases when 1.3502 + # they really should be! 1.3503 + if exceptionCode is None: 1.3504 + exceptionCode = "return false;\n" 1.3505 + # We often want exceptionCode to be indented, since it often appears in an 1.3506 + # if body. 1.3507 + exceptionCodeIndented = CGIndenter(CGGeneric(exceptionCode)) 1.3508 + 1.3509 + # Unfortunately, .capitalize() on a string will lowercase things inside the 1.3510 + # string, which we do not want. 1.3511 + def firstCap(string): 1.3512 + return string[0].upper() + string[1:] 1.3513 + 1.3514 + # Helper functions for dealing with failures due to the JS value being the 1.3515 + # wrong type of value 1.3516 + def onFailureNotAnObject(failureCode): 1.3517 + return CGGeneric( 1.3518 + failureCode or 1.3519 + ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n' 1.3520 + '%s' % (firstCap(sourceDescription), exceptionCode))) 1.3521 + 1.3522 + def onFailureBadType(failureCode, typeName): 1.3523 + return CGGeneric( 1.3524 + failureCode or 1.3525 + ('ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "%s", "%s");\n' 1.3526 + '%s' % (firstCap(sourceDescription), typeName, exceptionCode))) 1.3527 + 1.3528 + def onFailureNotCallable(failureCode): 1.3529 + return CGGeneric( 1.3530 + failureCode or 1.3531 + ('ThrowErrorMessage(cx, MSG_NOT_CALLABLE, "%s");\n' 1.3532 + '%s' % (firstCap(sourceDescription), exceptionCode))) 1.3533 + 1.3534 + # A helper function for handling default values. Takes a template 1.3535 + # body and the C++ code to set the default value and wraps the 1.3536 + # given template body in handling for the default value. 1.3537 + def handleDefault(template, setDefault): 1.3538 + if defaultValue is None: 1.3539 + return template 1.3540 + return ( 1.3541 + "if (${haveValue}) {\n" + 1.3542 + indent(template) + 1.3543 + "} else {\n" + 1.3544 + indent(setDefault) + 1.3545 + "}\n") 1.3546 + 1.3547 + # A helper function for handling null default values. Much like 1.3548 + # handleDefault, but checks that the default value, if it exists, is null. 1.3549 + def handleDefaultNull(template, codeToSetNull): 1.3550 + if (defaultValue is not None and 1.3551 + not isinstance(defaultValue, IDLNullValue)): 1.3552 + raise TypeError("Can't handle non-null default value here") 1.3553 + return handleDefault(template, codeToSetNull) 1.3554 + 1.3555 + # A helper function for wrapping up the template body for 1.3556 + # possibly-nullable objecty stuff 1.3557 + def wrapObjectTemplate(templateBody, type, codeToSetNull, failureCode=None): 1.3558 + if isNullOrUndefined and type.nullable(): 1.3559 + # Just ignore templateBody and set ourselves to null. 1.3560 + # Note that we don't have to worry about default values 1.3561 + # here either, since we already examined this value. 1.3562 + return codeToSetNull 1.3563 + 1.3564 + if not isDefinitelyObject: 1.3565 + # Handle the non-object cases by wrapping up the whole 1.3566 + # thing in an if cascade. 1.3567 + if type.nullable(): 1.3568 + elifLine = "} else if (${val}.isNullOrUndefined()) {\n" 1.3569 + elifBody = codeToSetNull 1.3570 + else: 1.3571 + elifLine = "" 1.3572 + elifBody = "" 1.3573 + 1.3574 + # Note that $${val} below expands to ${val}. This string is 1.3575 + # used as a template later, and val will be filled in then. 1.3576 + templateBody = fill( 1.3577 + """ 1.3578 + if ($${val}.isObject()) { 1.3579 + $*{templateBody} 1.3580 + $*{elifLine} 1.3581 + $*{elifBody} 1.3582 + } else { 1.3583 + $*{failureBody} 1.3584 + } 1.3585 + """, 1.3586 + templateBody=templateBody, 1.3587 + elifLine=elifLine, 1.3588 + elifBody=elifBody, 1.3589 + failureBody=onFailureNotAnObject(failureCode).define()) 1.3590 + 1.3591 + if type.nullable(): 1.3592 + templateBody = handleDefaultNull(templateBody, codeToSetNull) 1.3593 + else: 1.3594 + assert defaultValue is None 1.3595 + 1.3596 + return templateBody 1.3597 + 1.3598 + # A helper function for converting things that look like a JSObject*. 1.3599 + def handleJSObjectType(type, isMember, failureCode): 1.3600 + if not isMember: 1.3601 + if isOptional: 1.3602 + # We have a specialization of Optional that will use a 1.3603 + # Rooted for the storage here. 1.3604 + declType = CGGeneric("JS::Handle<JSObject*>") 1.3605 + else: 1.3606 + declType = CGGeneric("JS::Rooted<JSObject*>") 1.3607 + declArgs = "cx" 1.3608 + else: 1.3609 + assert (isMember in 1.3610 + ("Sequence", "Variadic", "Dictionary", "OwningUnion", "MozMap")) 1.3611 + # We'll get traced by the sequence or dictionary or union tracer 1.3612 + declType = CGGeneric("JSObject*") 1.3613 + declArgs = None 1.3614 + templateBody = "${declName} = &${val}.toObject();\n" 1.3615 + setToNullCode = "${declName} = nullptr;\n" 1.3616 + template = wrapObjectTemplate(templateBody, type, setToNullCode, 1.3617 + failureCode) 1.3618 + return JSToNativeConversionInfo(template, declType=declType, 1.3619 + dealWithOptional=isOptional, 1.3620 + declArgs=declArgs) 1.3621 + 1.3622 + assert not (isEnforceRange and isClamp) # These are mutually exclusive 1.3623 + 1.3624 + if type.isArray(): 1.3625 + raise TypeError("Can't handle array arguments yet") 1.3626 + 1.3627 + if type.isSequence(): 1.3628 + assert not isEnforceRange and not isClamp 1.3629 + 1.3630 + if failureCode is None: 1.3631 + notSequence = ('ThrowErrorMessage(cx, MSG_NOT_SEQUENCE, "%s");\n' 1.3632 + "%s" % (firstCap(sourceDescription), exceptionCode)) 1.3633 + else: 1.3634 + notSequence = failureCode 1.3635 + 1.3636 + nullable = type.nullable() 1.3637 + # Be very careful not to change "type": we need it later 1.3638 + if nullable: 1.3639 + elementType = type.inner.inner 1.3640 + else: 1.3641 + elementType = type.inner 1.3642 + 1.3643 + # We want to use auto arrays if we can, but we have to be careful with 1.3644 + # reallocation behavior for arrays. In particular, if we use auto 1.3645 + # arrays for sequences and have a sequence of elements which are 1.3646 + # themselves sequences or have sequences as members, we have a problem. 1.3647 + # In that case, resizing the outermost nsAutoTarray to the right size 1.3648 + # will memmove its elements, but nsAutoTArrays are not memmovable and 1.3649 + # hence will end up with pointers to bogus memory, which is bad. To 1.3650 + # deal with this, we typically map WebIDL sequences to our Sequence 1.3651 + # type, which is in fact memmovable. The one exception is when we're 1.3652 + # passing in a sequence directly as an argument without any sort of 1.3653 + # optional or nullable complexity going on. In that situation, we can 1.3654 + # use an AutoSequence instead. We have to keep using Sequence in the 1.3655 + # nullable and optional cases because we don't want to leak the 1.3656 + # AutoSequence type to consumers, which would be unavoidable with 1.3657 + # Nullable<AutoSequence> or Optional<AutoSequence>. 1.3658 + if isMember or isOptional or nullable or isCallbackReturnValue: 1.3659 + sequenceClass = "Sequence" 1.3660 + else: 1.3661 + sequenceClass = "binding_detail::AutoSequence" 1.3662 + 1.3663 + # XXXbz we can't include the index in the sourceDescription, because 1.3664 + # we don't really have a way to pass one in dynamically at runtime... 1.3665 + elementInfo = getJSToNativeConversionInfo( 1.3666 + elementType, descriptorProvider, isMember="Sequence", 1.3667 + exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode, 1.3668 + isCallbackReturnValue=isCallbackReturnValue, 1.3669 + sourceDescription="element of %s" % sourceDescription) 1.3670 + if elementInfo.dealWithOptional: 1.3671 + raise TypeError("Shouldn't have optional things in sequences") 1.3672 + if elementInfo.holderType is not None: 1.3673 + raise TypeError("Shouldn't need holders for sequences") 1.3674 + 1.3675 + typeName = CGTemplatedType(sequenceClass, elementInfo.declType) 1.3676 + sequenceType = typeName.define() 1.3677 + if nullable: 1.3678 + typeName = CGTemplatedType("Nullable", typeName) 1.3679 + arrayRef = "${declName}.SetValue()" 1.3680 + else: 1.3681 + arrayRef = "${declName}" 1.3682 + 1.3683 + elementConversion = string.Template(elementInfo.template).substitute({ 1.3684 + "val": "temp", 1.3685 + "mutableVal": "&temp", 1.3686 + "declName": "slot", 1.3687 + # We only need holderName here to handle isExternal() 1.3688 + # interfaces, which use an internal holder for the 1.3689 + # conversion even when forceOwningType ends up true. 1.3690 + "holderName": "tempHolder" 1.3691 + }) 1.3692 + 1.3693 + # NOTE: Keep this in sync with variadic conversions as needed 1.3694 + templateBody = fill( 1.3695 + """ 1.3696 + JS::ForOfIterator iter(cx); 1.3697 + if (!iter.init($${val}, JS::ForOfIterator::AllowNonIterable)) { 1.3698 + $*{exceptionCode} 1.3699 + } 1.3700 + if (!iter.valueIsIterable()) { 1.3701 + $*{notSequence} 1.3702 + } 1.3703 + ${sequenceType} &arr = ${arrayRef}; 1.3704 + JS::Rooted<JS::Value> temp(cx); 1.3705 + while (true) { 1.3706 + bool done; 1.3707 + if (!iter.next(&temp, &done)) { 1.3708 + $*{exceptionCode} 1.3709 + } 1.3710 + if (done) { 1.3711 + break; 1.3712 + } 1.3713 + ${elementType}* slotPtr = arr.AppendElement(); 1.3714 + if (!slotPtr) { 1.3715 + JS_ReportOutOfMemory(cx); 1.3716 + $*{exceptionCode} 1.3717 + } 1.3718 + ${elementType}& slot = *slotPtr; 1.3719 + $*{elementConversion} 1.3720 + } 1.3721 + """, 1.3722 + exceptionCode=exceptionCode, 1.3723 + notSequence=notSequence, 1.3724 + sequenceType=sequenceType, 1.3725 + arrayRef=arrayRef, 1.3726 + elementType=elementInfo.declType.define(), 1.3727 + elementConversion=elementConversion) 1.3728 + 1.3729 + templateBody = wrapObjectTemplate(templateBody, type, 1.3730 + "${declName}.SetNull();\n", notSequence) 1.3731 + # Sequence arguments that might contain traceable things need 1.3732 + # to get traced 1.3733 + if not isMember and typeNeedsRooting(elementType): 1.3734 + holderType = CGTemplatedType("SequenceRooter", elementInfo.declType) 1.3735 + # If our sequence is nullable, this will set the Nullable to be 1.3736 + # not-null, but that's ok because we make an explicit SetNull() call 1.3737 + # on it as needed if our JS value is actually null. 1.3738 + holderArgs = "cx, &%s" % arrayRef 1.3739 + else: 1.3740 + holderType = None 1.3741 + holderArgs = None 1.3742 + 1.3743 + return JSToNativeConversionInfo(templateBody, declType=typeName, 1.3744 + holderType=holderType, 1.3745 + dealWithOptional=isOptional, 1.3746 + holderArgs=holderArgs) 1.3747 + 1.3748 + if type.isMozMap(): 1.3749 + assert not isEnforceRange and not isClamp 1.3750 + if failureCode is None: 1.3751 + notMozMap = ('ThrowErrorMessage(cx, MSG_NOT_OBJECT, "%s");\n' 1.3752 + "%s" % (firstCap(sourceDescription), exceptionCode)) 1.3753 + else: 1.3754 + notMozMap = failureCode 1.3755 + 1.3756 + nullable = type.nullable() 1.3757 + # Be very careful not to change "type": we need it later 1.3758 + if nullable: 1.3759 + valueType = type.inner.inner 1.3760 + else: 1.3761 + valueType = type.inner 1.3762 + 1.3763 + valueInfo = getJSToNativeConversionInfo( 1.3764 + valueType, descriptorProvider, isMember="MozMap", 1.3765 + exceptionCode=exceptionCode, lenientFloatCode=lenientFloatCode, 1.3766 + isCallbackReturnValue=isCallbackReturnValue, 1.3767 + sourceDescription="value in %s" % sourceDescription) 1.3768 + if valueInfo.dealWithOptional: 1.3769 + raise TypeError("Shouldn't have optional things in MozMap") 1.3770 + if valueInfo.holderType is not None: 1.3771 + raise TypeError("Shouldn't need holders for MozMap") 1.3772 + 1.3773 + typeName = CGTemplatedType("MozMap", valueInfo.declType) 1.3774 + mozMapType = typeName.define() 1.3775 + if nullable: 1.3776 + typeName = CGTemplatedType("Nullable", typeName) 1.3777 + mozMapRef = "${declName}.SetValue()" 1.3778 + else: 1.3779 + mozMapRef = "${declName}" 1.3780 + 1.3781 + valueConversion = string.Template(valueInfo.template).substitute({ 1.3782 + "val": "temp", 1.3783 + "mutableVal": "&temp", 1.3784 + "declName": "slot", 1.3785 + # We only need holderName here to handle isExternal() 1.3786 + # interfaces, which use an internal holder for the 1.3787 + # conversion even when forceOwningType ends up true. 1.3788 + "holderName": "tempHolder" 1.3789 + }) 1.3790 + 1.3791 + templateBody = fill( 1.3792 + """ 1.3793 + ${mozMapType} &mozMap = ${mozMapRef}; 1.3794 + 1.3795 + JS::Rooted<JSObject*> mozMapObj(cx, &$${val}.toObject()); 1.3796 + JS::AutoIdArray ids(cx, JS_Enumerate(cx, mozMapObj)); 1.3797 + if (!ids) { 1.3798 + $*{exceptionCode} 1.3799 + } 1.3800 + JS::Rooted<JS::Value> propNameValue(cx); 1.3801 + JS::Rooted<JS::Value> temp(cx); 1.3802 + JS::Rooted<jsid> curId(cx); 1.3803 + for (size_t i = 0; i < ids.length(); ++i) { 1.3804 + // Make sure we get the value before converting the name, since 1.3805 + // getting the value can trigger GC but our name is a dependent 1.3806 + // string. 1.3807 + curId = ids[i]; 1.3808 + binding_detail::FakeDependentString propName; 1.3809 + if (!JS_GetPropertyById(cx, mozMapObj, curId, &temp) || 1.3810 + !JS_IdToValue(cx, curId, &propNameValue) || 1.3811 + !ConvertJSValueToString(cx, propNameValue, &propNameValue, 1.3812 + eStringify, eStringify, propName)) { 1.3813 + $*{exceptionCode} 1.3814 + } 1.3815 + 1.3816 + ${valueType}* slotPtr = mozMap.AddEntry(propName); 1.3817 + if (!slotPtr) { 1.3818 + JS_ReportOutOfMemory(cx); 1.3819 + $*{exceptionCode} 1.3820 + } 1.3821 + ${valueType}& slot = *slotPtr; 1.3822 + $*{valueConversion} 1.3823 + } 1.3824 + """, 1.3825 + exceptionCode=exceptionCode, 1.3826 + mozMapType=mozMapType, 1.3827 + mozMapRef=mozMapRef, 1.3828 + valueType=valueInfo.declType.define(), 1.3829 + valueConversion=valueConversion) 1.3830 + 1.3831 + templateBody = wrapObjectTemplate(templateBody, type, 1.3832 + "${declName}.SetNull();\n", 1.3833 + notMozMap) 1.3834 + 1.3835 + declType = typeName 1.3836 + declArgs = None 1.3837 + holderType = None 1.3838 + holderArgs = None 1.3839 + # MozMap arguments that might contain traceable things need 1.3840 + # to get traced 1.3841 + if not isMember and isCallbackReturnValue: 1.3842 + # Go ahead and just convert directly into our actual return value 1.3843 + declType = CGWrapper(declType, post="&") 1.3844 + declArgs = "aRetVal" 1.3845 + elif not isMember and typeNeedsRooting(valueType): 1.3846 + holderType = CGTemplatedType("MozMapRooter", valueInfo.declType) 1.3847 + # If our MozMap is nullable, this will set the Nullable to be 1.3848 + # not-null, but that's ok because we make an explicit SetNull() call 1.3849 + # on it as needed if our JS value is actually null. 1.3850 + holderArgs = "cx, &%s" % mozMapRef 1.3851 + 1.3852 + return JSToNativeConversionInfo(templateBody, declType=declType, 1.3853 + declArgs=declArgs, 1.3854 + holderType=holderType, 1.3855 + dealWithOptional=isOptional, 1.3856 + holderArgs=holderArgs) 1.3857 + 1.3858 + if type.isUnion(): 1.3859 + nullable = type.nullable() 1.3860 + if nullable: 1.3861 + type = type.inner 1.3862 + 1.3863 + unionArgumentObj = "${declName}" if isMember else "${holderName}" 1.3864 + if nullable: 1.3865 + # If we're a member, we're a Nullable, which hasn't been told it has 1.3866 + # a value. Otherwise we're an already-constructed Maybe. 1.3867 + unionArgumentObj += ".SetValue()" if isMember else ".ref()" 1.3868 + 1.3869 + memberTypes = type.flatMemberTypes 1.3870 + names = [] 1.3871 + 1.3872 + interfaceMemberTypes = filter(lambda t: t.isNonCallbackInterface(), memberTypes) 1.3873 + if len(interfaceMemberTypes) > 0: 1.3874 + interfaceObject = [] 1.3875 + for memberType in interfaceMemberTypes: 1.3876 + if type.isGeckoInterface(): 1.3877 + name = memberType.inner.identifier.name 1.3878 + else: 1.3879 + name = memberType.name 1.3880 + interfaceObject.append( 1.3881 + CGGeneric("(failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext" % 1.3882 + (unionArgumentObj, name))) 1.3883 + names.append(name) 1.3884 + interfaceObject = CGWrapper(CGList(interfaceObject, " ||\n"), 1.3885 + pre="done = ", post=";\n\n", reindent=True) 1.3886 + else: 1.3887 + interfaceObject = None 1.3888 + 1.3889 + arrayObjectMemberTypes = filter(lambda t: t.isArray() or t.isSequence(), memberTypes) 1.3890 + if len(arrayObjectMemberTypes) > 0: 1.3891 + raise TypeError("Bug 767924: We don't support sequences in unions yet") 1.3892 + else: 1.3893 + arrayObject = None 1.3894 + 1.3895 + dateObjectMemberTypes = filter(lambda t: t.isDate(), memberTypes) 1.3896 + if len(dateObjectMemberTypes) > 0: 1.3897 + assert len(dateObjectMemberTypes) == 1 1.3898 + memberType = dateObjectMemberTypes[0] 1.3899 + name = memberType.name 1.3900 + dateObject = CGGeneric("%s.SetTo%s(cx, ${val}, ${mutableVal});\n" 1.3901 + "done = true;\n" % (unionArgumentObj, name)) 1.3902 + dateObject = CGIfWrapper(dateObject, "JS_ObjectIsDate(cx, argObj)") 1.3903 + names.append(name) 1.3904 + else: 1.3905 + dateObject = None 1.3906 + 1.3907 + callbackMemberTypes = filter(lambda t: t.isCallback() or t.isCallbackInterface(), memberTypes) 1.3908 + if len(callbackMemberTypes) > 0: 1.3909 + assert len(callbackMemberTypes) == 1 1.3910 + memberType = callbackMemberTypes[0] 1.3911 + name = memberType.name 1.3912 + callbackObject = CGGeneric( 1.3913 + "done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n" % 1.3914 + (unionArgumentObj, name)) 1.3915 + names.append(name) 1.3916 + else: 1.3917 + callbackObject = None 1.3918 + 1.3919 + dictionaryMemberTypes = filter(lambda t: t.isDictionary(), memberTypes) 1.3920 + if len(dictionaryMemberTypes) > 0: 1.3921 + assert len(dictionaryMemberTypes) == 1 1.3922 + name = dictionaryMemberTypes[0].inner.identifier.name 1.3923 + setDictionary = CGGeneric( 1.3924 + "done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n" % 1.3925 + (unionArgumentObj, name)) 1.3926 + names.append(name) 1.3927 + else: 1.3928 + setDictionary = None 1.3929 + 1.3930 + mozMapMemberTypes = filter(lambda t: t.isMozMap(), memberTypes) 1.3931 + if len(mozMapMemberTypes) > 0: 1.3932 + raise TypeError("We don't support MozMap in unions yet") 1.3933 + 1.3934 + objectMemberTypes = filter(lambda t: t.isObject(), memberTypes) 1.3935 + if len(objectMemberTypes) > 0: 1.3936 + assert len(objectMemberTypes) == 1 1.3937 + # Very important to NOT construct a temporary Rooted here, since the 1.3938 + # SetToObject call can call a Rooted constructor and we need to keep 1.3939 + # stack discipline for Rooted. 1.3940 + object = CGGeneric("%s.SetToObject(cx, &${val}.toObject());\n" 1.3941 + "done = true;\n" % unionArgumentObj) 1.3942 + names.append(objectMemberTypes[0].name) 1.3943 + else: 1.3944 + object = None 1.3945 + 1.3946 + hasObjectTypes = interfaceObject or arrayObject or dateObject or callbackObject or object 1.3947 + if hasObjectTypes: 1.3948 + # "object" is not distinguishable from other types 1.3949 + assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject) 1.3950 + if arrayObject or dateObject or callbackObject: 1.3951 + # An object can be both an array object and a callback or 1.3952 + # dictionary, but we shouldn't have both in the union's members 1.3953 + # because they are not distinguishable. 1.3954 + assert not (arrayObject and callbackObject) 1.3955 + templateBody = CGElseChain([arrayObject, dateObject, callbackObject]) 1.3956 + else: 1.3957 + templateBody = None 1.3958 + if interfaceObject: 1.3959 + assert not object 1.3960 + if templateBody: 1.3961 + templateBody = CGIfWrapper(templateBody, "!done") 1.3962 + templateBody = CGList([interfaceObject, templateBody]) 1.3963 + else: 1.3964 + templateBody = CGList([templateBody, object]) 1.3965 + 1.3966 + if dateObject: 1.3967 + templateBody.prepend(CGGeneric("JS::Rooted<JSObject*> argObj(cx, &${val}.toObject());\n")) 1.3968 + templateBody = CGIfWrapper(templateBody, "${val}.isObject()") 1.3969 + else: 1.3970 + templateBody = CGGeneric() 1.3971 + 1.3972 + if setDictionary: 1.3973 + assert not object 1.3974 + templateBody = CGList([templateBody, 1.3975 + CGIfWrapper(setDictionary, "!done")]) 1.3976 + 1.3977 + stringTypes = [t for t in memberTypes if t.isString() or t.isEnum()] 1.3978 + numericTypes = [t for t in memberTypes if t.isNumeric()] 1.3979 + booleanTypes = [t for t in memberTypes if t.isBoolean()] 1.3980 + if stringTypes or numericTypes or booleanTypes: 1.3981 + assert len(stringTypes) <= 1 1.3982 + assert len(numericTypes) <= 1 1.3983 + assert len(booleanTypes) <= 1 1.3984 + 1.3985 + # We will wrap all this stuff in a do { } while (0); so we 1.3986 + # can use "break" for flow control. 1.3987 + def getStringOrPrimitiveConversion(memberType): 1.3988 + if memberType.isEnum(): 1.3989 + name = memberType.inner.identifier.name 1.3990 + else: 1.3991 + name = memberType.name 1.3992 + return CGGeneric("done = (failed = !%s.TrySetTo%s(cx, ${val}, ${mutableVal}, tryNext)) || !tryNext;\n" 1.3993 + "break;\n" % (unionArgumentObj, name)) 1.3994 + other = CGList([]) 1.3995 + stringConversion = map(getStringOrPrimitiveConversion, stringTypes) 1.3996 + numericConversion = map(getStringOrPrimitiveConversion, numericTypes) 1.3997 + booleanConversion = map(getStringOrPrimitiveConversion, booleanTypes) 1.3998 + if stringConversion: 1.3999 + if booleanConversion: 1.4000 + other.append(CGIfWrapper(booleanConversion[0], 1.4001 + "${val}.isBoolean()")) 1.4002 + if numericConversion: 1.4003 + other.append(CGIfWrapper(numericConversion[0], 1.4004 + "${val}.isNumber()")) 1.4005 + other.append(stringConversion[0]) 1.4006 + elif numericConversion: 1.4007 + if booleanConversion: 1.4008 + other.append(CGIfWrapper(booleanConversion[0], 1.4009 + "${val}.isBoolean()")) 1.4010 + other.append(numericConversion[0]) 1.4011 + else: 1.4012 + assert booleanConversion 1.4013 + other.append(booleanConversion[0]) 1.4014 + 1.4015 + other = CGWrapper(CGIndenter(other), pre="do {\n", post="} while (0);\n") 1.4016 + if hasObjectTypes or setDictionary: 1.4017 + other = CGWrapper(CGIndenter(other), "{\n", post="}\n") 1.4018 + if object: 1.4019 + templateBody = CGElseChain([templateBody, other]) 1.4020 + else: 1.4021 + other = CGWrapper(other, pre="if (!done) ") 1.4022 + templateBody = CGList([templateBody, other]) 1.4023 + else: 1.4024 + assert templateBody.define() == "" 1.4025 + templateBody = other 1.4026 + else: 1.4027 + other = None 1.4028 + 1.4029 + templateBody = CGWrapper(templateBody, pre="bool done = false, failed = false, tryNext;\n") 1.4030 + throw = CGGeneric(fill( 1.4031 + """ 1.4032 + if (failed) { 1.4033 + $*{exceptionCode} 1.4034 + } 1.4035 + if (!done) { 1.4036 + ThrowErrorMessage(cx, MSG_NOT_IN_UNION, "${desc}", "${names}"); 1.4037 + $*{exceptionCode} 1.4038 + } 1.4039 + """, 1.4040 + exceptionCode=exceptionCode, 1.4041 + desc=firstCap(sourceDescription), 1.4042 + names=", ".join(names))) 1.4043 + 1.4044 + templateBody = CGWrapper(CGIndenter(CGList([templateBody, throw])), pre="{\n", post="}\n") 1.4045 + 1.4046 + typeName = CGUnionStruct.unionTypeDecl(type, isMember) 1.4047 + argumentTypeName = typeName + "Argument" 1.4048 + if nullable: 1.4049 + typeName = "Nullable<" + typeName + " >" 1.4050 + 1.4051 + def handleNull(templateBody, setToNullVar, extraConditionForNull=""): 1.4052 + nullTest = "%s${val}.isNullOrUndefined()" % extraConditionForNull 1.4053 + return CGIfElseWrapper(nullTest, 1.4054 + CGGeneric("%s.SetNull();\n" % setToNullVar), 1.4055 + templateBody) 1.4056 + 1.4057 + if type.hasNullableType: 1.4058 + assert not nullable 1.4059 + # Make sure to handle a null default value here 1.4060 + if defaultValue and isinstance(defaultValue, IDLNullValue): 1.4061 + assert defaultValue.type == type 1.4062 + extraConditionForNull = "!(${haveValue}) || " 1.4063 + else: 1.4064 + extraConditionForNull = "" 1.4065 + templateBody = handleNull(templateBody, unionArgumentObj, 1.4066 + extraConditionForNull=extraConditionForNull) 1.4067 + 1.4068 + declType = CGGeneric(typeName) 1.4069 + if isMember: 1.4070 + holderType = None 1.4071 + else: 1.4072 + holderType = CGGeneric(argumentTypeName) 1.4073 + if nullable: 1.4074 + holderType = CGTemplatedType("Maybe", holderType) 1.4075 + 1.4076 + # If we're isOptional and not nullable the normal optional handling will 1.4077 + # handle lazy construction of our holder. If we're nullable and not 1.4078 + # isMember we do it all by hand because we do not want our holder 1.4079 + # constructed if we're null. But if we're isMember we don't have a 1.4080 + # holder anyway, so we can do the normal Optional codepath. 1.4081 + declLoc = "${declName}" 1.4082 + constructDecl = None 1.4083 + if nullable: 1.4084 + if isOptional and not isMember: 1.4085 + holderArgs = "${declName}.Value().SetValue()" 1.4086 + declType = CGTemplatedType("Optional", declType) 1.4087 + constructDecl = CGGeneric("${declName}.Construct();\n") 1.4088 + declLoc = "${declName}.Value()" 1.4089 + else: 1.4090 + holderArgs = "${declName}.SetValue()" 1.4091 + if holderType is not None: 1.4092 + constructHolder = CGGeneric("${holderName}.construct(%s);\n" % holderArgs) 1.4093 + else: 1.4094 + constructHolder = None 1.4095 + # Don't need to pass those args when the holder is being constructed 1.4096 + holderArgs = None 1.4097 + else: 1.4098 + holderArgs = "${declName}" 1.4099 + constructHolder = None 1.4100 + 1.4101 + if defaultValue and not isinstance(defaultValue, IDLNullValue): 1.4102 + tag = defaultValue.type.tag() 1.4103 + 1.4104 + if tag in numericSuffixes or tag is IDLType.Tags.bool: 1.4105 + defaultStr = getHandleDefault(defaultValue) 1.4106 + value = declLoc + (".Value()" if nullable else "") 1.4107 + default = CGGeneric("%s.RawSetAs%s() = %s;\n" % 1.4108 + (value, defaultValue.type, defaultStr)) 1.4109 + else: 1.4110 + default = CGGeneric( 1.4111 + handleDefaultStringValue( 1.4112 + defaultValue, "%s.SetStringData" % unionArgumentObj) + 1.4113 + ";\n") 1.4114 + 1.4115 + templateBody = CGIfElseWrapper("!(${haveValue})", default, templateBody) 1.4116 + 1.4117 + templateBody = CGList([constructHolder, templateBody]) 1.4118 + 1.4119 + if nullable: 1.4120 + if defaultValue: 1.4121 + if isinstance(defaultValue, IDLNullValue): 1.4122 + extraConditionForNull = "!(${haveValue}) || " 1.4123 + else: 1.4124 + extraConditionForNull = "${haveValue} && " 1.4125 + else: 1.4126 + extraConditionForNull = "" 1.4127 + templateBody = handleNull(templateBody, declLoc, 1.4128 + extraConditionForNull=extraConditionForNull) 1.4129 + elif (not type.hasNullableType and defaultValue and 1.4130 + isinstance(defaultValue, IDLNullValue)): 1.4131 + assert type.hasDictionaryType 1.4132 + assert defaultValue.type.isDictionary() 1.4133 + if not isMember and typeNeedsRooting(defaultValue.type): 1.4134 + ctorArgs = "cx" 1.4135 + else: 1.4136 + ctorArgs = "" 1.4137 + initDictionaryWithNull = CGIfWrapper( 1.4138 + CGGeneric("return false;\n"), 1.4139 + ('!%s.RawSetAs%s(%s).Init(cx, JS::NullHandleValue, "Member of %s")' 1.4140 + % (declLoc, getUnionMemberName(defaultValue.type), 1.4141 + ctorArgs, type))) 1.4142 + templateBody = CGIfElseWrapper("!(${haveValue})", 1.4143 + initDictionaryWithNull, 1.4144 + templateBody) 1.4145 + 1.4146 + templateBody = CGList([constructDecl, templateBody]) 1.4147 + 1.4148 + return JSToNativeConversionInfo(templateBody.define(), 1.4149 + declType=declType, 1.4150 + holderType=holderType, 1.4151 + holderArgs=holderArgs, 1.4152 + dealWithOptional=isOptional and (not nullable or isMember)) 1.4153 + 1.4154 + if type.isGeckoInterface(): 1.4155 + assert not isEnforceRange and not isClamp 1.4156 + 1.4157 + descriptor = descriptorProvider.getDescriptor( 1.4158 + type.unroll().inner.identifier.name) 1.4159 + 1.4160 + if descriptor.nativeType == 'JSObject': 1.4161 + # XXXbz Workers code does this sometimes 1.4162 + assert descriptor.workers 1.4163 + return handleJSObjectType(type, isMember, failureCode) 1.4164 + 1.4165 + if descriptor.interface.isCallback(): 1.4166 + name = descriptor.interface.identifier.name 1.4167 + if type.nullable() or isCallbackReturnValue: 1.4168 + declType = CGGeneric("nsRefPtr<%s>" % name) 1.4169 + else: 1.4170 + declType = CGGeneric("OwningNonNull<%s>" % name) 1.4171 + # BOGUS extra blank line here turns out to be at the end of a block: 1.4172 + conversion = indent(CGCallbackTempRoot(name).define()) + "\n" 1.4173 + 1.4174 + template = wrapObjectTemplate(conversion, type, 1.4175 + "${declName} = nullptr;\n", 1.4176 + failureCode) 1.4177 + return JSToNativeConversionInfo(template, declType=declType, 1.4178 + dealWithOptional=isOptional) 1.4179 + 1.4180 + # This is an interface that we implement as a concrete class 1.4181 + # or an XPCOM interface. 1.4182 + 1.4183 + # Allow null pointers for nullable types and old-binding classes, and 1.4184 + # use an nsRefPtr or raw pointer for callback return values to make 1.4185 + # them easier to return. 1.4186 + argIsPointer = (type.nullable() or type.unroll().inner.isExternal() or 1.4187 + isCallbackReturnValue) 1.4188 + 1.4189 + # Sequences and non-worker callbacks have to hold a strong ref to the 1.4190 + # thing being passed down. Union return values must hold a strong ref 1.4191 + # because they may be returning an addrefed pointer. 1.4192 + # Also, callback return values always end up 1.4193 + # addrefing anyway, so there is no point trying to avoid it here and it 1.4194 + # makes other things simpler since we can assume the return value is a 1.4195 + # strong ref. 1.4196 + forceOwningType = ((descriptor.interface.isCallback() and 1.4197 + not descriptor.workers) or 1.4198 + isMember or 1.4199 + isCallbackReturnValue) 1.4200 + 1.4201 + if forceOwningType and descriptor.nativeOwnership == 'owned': 1.4202 + raise TypeError("Interface %s has 'owned' nativeOwnership, so we " 1.4203 + "don't know how to keep it alive in %s" % 1.4204 + (descriptor.interface.identifier.name, 1.4205 + sourceDescription)) 1.4206 + 1.4207 + typeName = descriptor.nativeType 1.4208 + typePtr = typeName + "*" 1.4209 + 1.4210 + # Compute a few things: 1.4211 + # - declType is the type we want to return as the first element of our 1.4212 + # tuple. 1.4213 + # - holderType is the type we want to return as the third element 1.4214 + # of our tuple. 1.4215 + 1.4216 + # Set up some sensible defaults for these things insofar as we can. 1.4217 + holderType = None 1.4218 + if argIsPointer: 1.4219 + if forceOwningType: 1.4220 + declType = "nsRefPtr<" + typeName + ">" 1.4221 + else: 1.4222 + declType = typePtr 1.4223 + else: 1.4224 + if forceOwningType: 1.4225 + declType = "OwningNonNull<" + typeName + ">" 1.4226 + else: 1.4227 + declType = "NonNull<" + typeName + ">" 1.4228 + 1.4229 + templateBody = "" 1.4230 + if not descriptor.skipGen and not descriptor.interface.isConsequential() and not descriptor.interface.isExternal(): 1.4231 + if failureCode is not None: 1.4232 + templateBody += str(CastableObjectUnwrapper( 1.4233 + descriptor, 1.4234 + "&${val}.toObject()", 1.4235 + "${declName}", 1.4236 + failureCode)) 1.4237 + else: 1.4238 + templateBody += str(FailureFatalCastableObjectUnwrapper( 1.4239 + descriptor, 1.4240 + "&${val}.toObject()", 1.4241 + "${declName}", 1.4242 + exceptionCode, 1.4243 + isCallbackReturnValue, 1.4244 + firstCap(sourceDescription))) 1.4245 + elif descriptor.workers: 1.4246 + return handleJSObjectType(type, isMember, failureCode) 1.4247 + else: 1.4248 + # Either external, or new-binding non-castable. We always have a 1.4249 + # holder for these, because we don't actually know whether we have 1.4250 + # to addref when unwrapping or not. So we just pass an 1.4251 + # getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release 1.4252 + # it'll put a non-null pointer in there. 1.4253 + if forceOwningType: 1.4254 + # Don't return a holderType in this case; our declName 1.4255 + # will just own stuff. 1.4256 + templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n" 1.4257 + else: 1.4258 + holderType = "nsRefPtr<" + typeName + ">" 1.4259 + templateBody += ( 1.4260 + "JS::Rooted<JS::Value> tmpVal(cx, ${val});\n" + 1.4261 + typePtr + " tmp;\n" 1.4262 + "if (NS_FAILED(UnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n") 1.4263 + templateBody += CGIndenter(onFailureBadType(failureCode, 1.4264 + descriptor.interface.identifier.name)).define() 1.4265 + templateBody += ("}\n" 1.4266 + "MOZ_ASSERT(tmp);\n") 1.4267 + 1.4268 + if not isDefinitelyObject and not forceOwningType: 1.4269 + # Our tmpVal will go out of scope, so we can't rely on it 1.4270 + # for rooting 1.4271 + templateBody += dedent(""" 1.4272 + if (tmpVal != ${val} && !${holderName}) { 1.4273 + // We have to have a strong ref, because we got this off 1.4274 + // some random object that might get GCed 1.4275 + ${holderName} = tmp; 1.4276 + } 1.4277 + """) 1.4278 + 1.4279 + # And store our tmp, before it goes out of scope. 1.4280 + templateBody += "${declName} = tmp;\n" 1.4281 + 1.4282 + # Just pass failureCode, not onFailureBadType, here, so we'll report the 1.4283 + # thing as not an object as opposed to not implementing whatever our 1.4284 + # interface is. 1.4285 + templateBody = wrapObjectTemplate(templateBody, type, 1.4286 + "${declName} = nullptr;\n", failureCode) 1.4287 + 1.4288 + declType = CGGeneric(declType) 1.4289 + if holderType is not None: 1.4290 + holderType = CGGeneric(holderType) 1.4291 + return JSToNativeConversionInfo(templateBody, 1.4292 + declType=declType, 1.4293 + holderType=holderType, 1.4294 + dealWithOptional=isOptional) 1.4295 + 1.4296 + if type.isSpiderMonkeyInterface(): 1.4297 + assert not isEnforceRange and not isClamp 1.4298 + name = type.name 1.4299 + arrayType = CGGeneric(name) 1.4300 + declType = arrayType 1.4301 + if type.nullable(): 1.4302 + declType = CGTemplatedType("Nullable", declType) 1.4303 + objRef = "${declName}.SetValue()" 1.4304 + else: 1.4305 + objRef = "${declName}" 1.4306 + 1.4307 + # Again, this is a bit strange since we are actually building a 1.4308 + # template string here. ${objRef} and $*{badType} below are filled in 1.4309 + # right now; $${val} expands to ${val}, to be filled in later. 1.4310 + template = fill( 1.4311 + """ 1.4312 + if (!${objRef}.Init(&$${val}.toObject())) { 1.4313 + $*{badType} 1.4314 + } 1.4315 + 1.4316 + """, # BOGUS extra blank line 1.4317 + objRef=objRef, 1.4318 + badType=onFailureBadType(failureCode, type.name).define()) 1.4319 + template = wrapObjectTemplate(template, type, "${declName}.SetNull();\n", 1.4320 + failureCode) 1.4321 + if not isMember: 1.4322 + # This is a bit annoying. In a union we don't want to have a 1.4323 + # holder, since unions don't support that. But if we're optional we 1.4324 + # want to have a holder, so that the callee doesn't see 1.4325 + # Optional<RootedTypedArray<ArrayType> >. So do a holder if we're 1.4326 + # optional and use a RootedTypedArray otherwise. 1.4327 + if isOptional: 1.4328 + holderType = CGTemplatedType("TypedArrayRooter", arrayType) 1.4329 + # If our typed array is nullable, this will set the Nullable to 1.4330 + # be not-null, but that's ok because we make an explicit 1.4331 + # SetNull() call on it as needed if our JS value is actually 1.4332 + # null. XXXbz Because "Maybe" takes const refs for constructor 1.4333 + # arguments, we can't pass a reference here; have to pass a 1.4334 + # pointer. 1.4335 + holderArgs = "cx, &%s" % objRef 1.4336 + declArgs = None 1.4337 + else: 1.4338 + holderType = None 1.4339 + holderArgs = None 1.4340 + declType = CGTemplatedType("RootedTypedArray", declType) 1.4341 + declArgs = "cx" 1.4342 + else: 1.4343 + holderType = None 1.4344 + holderArgs = None 1.4345 + declArgs = None 1.4346 + return JSToNativeConversionInfo(template, 1.4347 + declType=declType, 1.4348 + holderType=holderType, 1.4349 + dealWithOptional=isOptional, 1.4350 + declArgs=declArgs, 1.4351 + holderArgs=holderArgs) 1.4352 + 1.4353 + if type.isDOMString(): 1.4354 + assert not isEnforceRange and not isClamp 1.4355 + 1.4356 + treatAs = { 1.4357 + "Default": "eStringify", 1.4358 + "EmptyString": "eEmpty", 1.4359 + "Null": "eNull", 1.4360 + } 1.4361 + if type.nullable(): 1.4362 + # For nullable strings null becomes a null string. 1.4363 + treatNullAs = "Null" 1.4364 + # For nullable strings undefined also becomes a null string. 1.4365 + undefinedBehavior = "eNull" 1.4366 + else: 1.4367 + undefinedBehavior = "eStringify" 1.4368 + nullBehavior = treatAs[treatNullAs] 1.4369 + 1.4370 + def getConversionCode(varName): 1.4371 + conversionCode = ( 1.4372 + "if (!ConvertJSValueToString(cx, ${val}, ${mutableVal}, %s, %s, %s)) {\n" 1.4373 + "%s" 1.4374 + "}\n" % (nullBehavior, undefinedBehavior, varName, 1.4375 + exceptionCodeIndented.define())) 1.4376 + if defaultValue is None: 1.4377 + return conversionCode 1.4378 + 1.4379 + if isinstance(defaultValue, IDLNullValue): 1.4380 + assert(type.nullable()) 1.4381 + defaultCode = "%s.SetNull()" % varName 1.4382 + else: 1.4383 + defaultCode = handleDefaultStringValue(defaultValue, 1.4384 + "%s.SetData" % varName) 1.4385 + return handleDefault(conversionCode, defaultCode + ";\n") 1.4386 + 1.4387 + if isMember: 1.4388 + # We have to make a copy, except in the variadic case, because our 1.4389 + # jsval may well not live as long as our string needs to. 1.4390 + declType = CGGeneric("nsString") 1.4391 + if isMember == "Variadic": 1.4392 + # The string is kept alive by the argument, so we can just 1.4393 + # depend on it. 1.4394 + assignString = "${declName}.Rebind(str.Data(), str.Length());\n" 1.4395 + else: 1.4396 + assignString = "${declName} = str;\n" 1.4397 + return JSToNativeConversionInfo( 1.4398 + fill( 1.4399 + """ 1.4400 + { 1.4401 + binding_detail::FakeDependentString str; 1.4402 + $*{convert} 1.4403 + $*{assign} 1.4404 + } 1.4405 + 1.4406 + """, # BOGUS extra newline 1.4407 + convert=getConversionCode("str"), 1.4408 + assign=assignString), 1.4409 + declType=declType, 1.4410 + dealWithOptional=isOptional) 1.4411 + 1.4412 + if isOptional: 1.4413 + declType = "Optional<nsAString>" 1.4414 + holderType = CGGeneric("binding_detail::FakeDependentString") 1.4415 + conversionCode = ("%s" 1.4416 + "${declName} = &${holderName};\n" % 1.4417 + getConversionCode("${holderName}")) 1.4418 + else: 1.4419 + declType = "binding_detail::FakeDependentString" 1.4420 + holderType = None 1.4421 + conversionCode = getConversionCode("${declName}") 1.4422 + 1.4423 + # No need to deal with optional here; we handled it already 1.4424 + return JSToNativeConversionInfo( 1.4425 + conversionCode, 1.4426 + declType=CGGeneric(declType), 1.4427 + holderType=holderType) 1.4428 + 1.4429 + if type.isByteString(): 1.4430 + assert not isEnforceRange and not isClamp 1.4431 + 1.4432 + nullable = toStringBool(type.nullable()) 1.4433 + 1.4434 + conversionCode = ( 1.4435 + "if (!ConvertJSValueToByteString(cx, ${val}, ${mutableVal}, %s, ${declName})) {\n" 1.4436 + "%s" 1.4437 + "}\n" % (nullable, exceptionCodeIndented.define())) 1.4438 + # ByteString arguments cannot have a default value. 1.4439 + assert defaultValue is None 1.4440 + 1.4441 + return JSToNativeConversionInfo( 1.4442 + conversionCode, 1.4443 + declType=CGGeneric("nsCString"), 1.4444 + dealWithOptional=isOptional) 1.4445 + 1.4446 + if type.isEnum(): 1.4447 + assert not isEnforceRange and not isClamp 1.4448 + 1.4449 + enumName = type.unroll().inner.identifier.name 1.4450 + declType = CGGeneric(enumName) 1.4451 + if type.nullable(): 1.4452 + declType = CGTemplatedType("Nullable", declType) 1.4453 + declType = declType.define() 1.4454 + enumLoc = "${declName}.SetValue()" 1.4455 + else: 1.4456 + enumLoc = "${declName}" 1.4457 + declType = declType.define() 1.4458 + 1.4459 + if invalidEnumValueFatal: 1.4460 + handleInvalidEnumValueCode = "MOZ_ASSERT(index >= 0);\n" 1.4461 + else: 1.4462 + # invalidEnumValueFatal is false only for attributes. So we won't 1.4463 + # have a non-default exceptionCode here unless attribute "arg 1.4464 + # conversion" code starts passing in an exceptionCode. At which 1.4465 + # point we'll need to figure out what that even means. 1.4466 + assert exceptionCode == "return false;\n" 1.4467 + handleInvalidEnumValueCode = dedent(""" 1.4468 + if (index < 0) { 1.4469 + return true; 1.4470 + } 1.4471 + """) 1.4472 + 1.4473 + template = fill( 1.4474 + """ 1.4475 + { 1.4476 + bool ok; 1.4477 + int index = FindEnumStringIndex<${invalidEnumValueFatal}>(cx, $${val}, ${values}, "${enumtype}", "${sourceDescription}", &ok); 1.4478 + if (!ok) { 1.4479 + $*{exceptionCode} 1.4480 + } 1.4481 + $*{handleInvalidEnumValueCode} 1.4482 + ${enumLoc} = static_cast<${enumtype}>(index); 1.4483 + } 1.4484 + """, 1.4485 + enumtype=enumName, 1.4486 + values=enumName + "Values::" + ENUM_ENTRY_VARIABLE_NAME, 1.4487 + invalidEnumValueFatal=toStringBool(invalidEnumValueFatal), 1.4488 + handleInvalidEnumValueCode=handleInvalidEnumValueCode, 1.4489 + exceptionCode=exceptionCode, 1.4490 + enumLoc=enumLoc, 1.4491 + sourceDescription=firstCap(sourceDescription)) 1.4492 + 1.4493 + setNull = "${declName}.SetNull();\n" 1.4494 + 1.4495 + if type.nullable(): 1.4496 + template = CGIfElseWrapper("${val}.isNullOrUndefined()", 1.4497 + CGGeneric(setNull), 1.4498 + CGGeneric(template)).define() 1.4499 + 1.4500 + if defaultValue is not None: 1.4501 + if isinstance(defaultValue, IDLNullValue): 1.4502 + assert type.nullable() 1.4503 + template = handleDefault(template, setNull) 1.4504 + else: 1.4505 + assert(defaultValue.type.tag() == IDLType.Tags.domstring) 1.4506 + template = handleDefault(template, 1.4507 + ("%s = %s::%s;\n" % 1.4508 + (enumLoc, enumName, 1.4509 + getEnumValueName(defaultValue.value)))) 1.4510 + return JSToNativeConversionInfo(template, declType=CGGeneric(declType), 1.4511 + dealWithOptional=isOptional) 1.4512 + 1.4513 + if type.isCallback(): 1.4514 + assert not isEnforceRange and not isClamp 1.4515 + assert not type.treatNonCallableAsNull() or type.nullable() 1.4516 + assert not type.treatNonObjectAsNull() or type.nullable() 1.4517 + assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull() 1.4518 + 1.4519 + name = type.unroll().identifier.name 1.4520 + if type.nullable(): 1.4521 + declType = CGGeneric("nsRefPtr<%s>" % name) 1.4522 + else: 1.4523 + declType = CGGeneric("OwningNonNull<%s>" % name) 1.4524 + conversion = indent(CGCallbackTempRoot(name).define()) 1.4525 + 1.4526 + if allowTreatNonCallableAsNull and type.treatNonCallableAsNull(): 1.4527 + haveCallable = "JS_ObjectIsCallable(cx, &${val}.toObject())" 1.4528 + if not isDefinitelyObject: 1.4529 + haveCallable = "${val}.isObject() && " + haveCallable 1.4530 + if defaultValue is not None: 1.4531 + assert(isinstance(defaultValue, IDLNullValue)) 1.4532 + haveCallable = "${haveValue} && " + haveCallable 1.4533 + template = ( 1.4534 + ("if (%s) {\n" % haveCallable) + 1.4535 + conversion + 1.4536 + "} else {\n" 1.4537 + " ${declName} = nullptr;\n" 1.4538 + "}\n") 1.4539 + elif allowTreatNonCallableAsNull and type.treatNonObjectAsNull(): 1.4540 + if not isDefinitelyObject: 1.4541 + haveObject = "${val}.isObject()" 1.4542 + if defaultValue is not None: 1.4543 + assert(isinstance(defaultValue, IDLNullValue)) 1.4544 + haveObject = "${haveValue} && " + haveObject 1.4545 + template = CGIfElseWrapper(haveObject, 1.4546 + CGGeneric(conversion + "\n"), # BOGUS extra blank line 1.4547 + CGGeneric("${declName} = nullptr;\n")).define() 1.4548 + else: 1.4549 + template = conversion 1.4550 + else: 1.4551 + template = wrapObjectTemplate( 1.4552 + "if (JS_ObjectIsCallable(cx, &${val}.toObject())) {\n" + 1.4553 + conversion + 1.4554 + "} else {\n" + 1.4555 + indent(onFailureNotCallable(failureCode).define()) + 1.4556 + "}\n", 1.4557 + type, 1.4558 + "${declName} = nullptr;\n", 1.4559 + failureCode) 1.4560 + return JSToNativeConversionInfo(template, declType=declType, 1.4561 + dealWithOptional=isOptional) 1.4562 + 1.4563 + if type.isAny(): 1.4564 + assert not isEnforceRange and not isClamp 1.4565 + 1.4566 + declArgs = None 1.4567 + if isMember in ("Variadic", "Sequence", "Dictionary", "MozMap"): 1.4568 + # Rooting is handled by the sequence and dictionary tracers. 1.4569 + declType = "JS::Value" 1.4570 + else: 1.4571 + assert not isMember 1.4572 + declType = "JS::Rooted<JS::Value>" 1.4573 + declArgs = "cx" 1.4574 + 1.4575 + assert not isOptional 1.4576 + templateBody = "${declName} = ${val};\n" 1.4577 + # We may not have a default value if we're being converted for 1.4578 + # a setter, say. 1.4579 + if defaultValue: 1.4580 + if isinstance(defaultValue, IDLNullValue): 1.4581 + defaultHandling = "${declName} = JS::NullValue();\n" 1.4582 + else: 1.4583 + assert isinstance(defaultValue, IDLUndefinedValue) 1.4584 + defaultHandling = "${declName} = JS::UndefinedValue();\n" 1.4585 + templateBody = handleDefault(templateBody, defaultHandling) 1.4586 + return JSToNativeConversionInfo(templateBody, 1.4587 + declType=CGGeneric(declType), 1.4588 + declArgs=declArgs) 1.4589 + 1.4590 + if type.isObject(): 1.4591 + assert not isEnforceRange and not isClamp 1.4592 + return handleJSObjectType(type, isMember, failureCode) 1.4593 + 1.4594 + if type.isDictionary(): 1.4595 + # There are no nullable dictionaries 1.4596 + assert not type.nullable() or isCallbackReturnValue 1.4597 + # All optional dictionaries always have default values, so we 1.4598 + # should be able to assume not isOptional here. 1.4599 + assert not isOptional 1.4600 + # In the callback return value case we never have to worry 1.4601 + # about a default value; we always have a value. 1.4602 + assert not isCallbackReturnValue or defaultValue is None 1.4603 + 1.4604 + typeName = CGDictionary.makeDictionaryName(type.unroll().inner) 1.4605 + if not isMember and not isCallbackReturnValue: 1.4606 + # Since we're not a member and not nullable or optional, no one will 1.4607 + # see our real type, so we can do the fast version of the dictionary 1.4608 + # that doesn't pre-initialize members. 1.4609 + typeName = "binding_detail::Fast" + typeName 1.4610 + 1.4611 + declType = CGGeneric(typeName) 1.4612 + 1.4613 + # We do manual default value handling here, because we 1.4614 + # actually do want a jsval, and we only handle null anyway 1.4615 + # NOTE: if isNullOrUndefined or isDefinitelyObject are true, 1.4616 + # we know we have a value, so we don't have to worry about the 1.4617 + # default value. 1.4618 + if (not isNullOrUndefined and not isDefinitelyObject and 1.4619 + defaultValue is not None): 1.4620 + assert(isinstance(defaultValue, IDLNullValue)) 1.4621 + val = "(${haveValue}) ? ${val} : JS::NullHandleValue" 1.4622 + else: 1.4623 + val = "${val}" 1.4624 + 1.4625 + if failureCode is not None: 1.4626 + if isDefinitelyObject: 1.4627 + dictionaryTest = "IsObjectValueConvertibleToDictionary" 1.4628 + else: 1.4629 + dictionaryTest = "IsConvertibleToDictionary" 1.4630 + # Check that the value we have can in fact be converted to 1.4631 + # a dictionary, and return failureCode if not. 1.4632 + template = CGIfWrapper( 1.4633 + CGGeneric(failureCode), 1.4634 + "!%s(cx, ${val})" % dictionaryTest).define() + "\n" 1.4635 + else: 1.4636 + template = "" 1.4637 + 1.4638 + dictLoc = "${declName}" 1.4639 + if type.nullable(): 1.4640 + dictLoc += ".SetValue()" 1.4641 + 1.4642 + template += ('if (!%s.Init(cx, %s, "%s")) {\n' 1.4643 + "%s" 1.4644 + "}\n" % (dictLoc, val, firstCap(sourceDescription), 1.4645 + exceptionCodeIndented.define())) 1.4646 + 1.4647 + if type.nullable(): 1.4648 + declType = CGTemplatedType("Nullable", declType) 1.4649 + template = CGIfElseWrapper("${val}.isNullOrUndefined()", 1.4650 + CGGeneric("${declName}.SetNull();\n"), 1.4651 + CGGeneric(template)).define() 1.4652 + 1.4653 + # Dictionary arguments that might contain traceable things need to get 1.4654 + # traced 1.4655 + if not isMember and isCallbackReturnValue: 1.4656 + # Go ahead and just convert directly into our actual return value 1.4657 + declType = CGWrapper(declType, post="&") 1.4658 + declArgs = "aRetVal" 1.4659 + elif not isMember and typeNeedsRooting(type): 1.4660 + declType = CGTemplatedType("RootedDictionary", declType) 1.4661 + declArgs = "cx" 1.4662 + else: 1.4663 + declArgs = None 1.4664 + 1.4665 + return JSToNativeConversionInfo(template, declType=declType, 1.4666 + declArgs=declArgs) 1.4667 + 1.4668 + if type.isVoid(): 1.4669 + assert not isOptional 1.4670 + # This one only happens for return values, and its easy: Just 1.4671 + # ignore the jsval. 1.4672 + return JSToNativeConversionInfo("") 1.4673 + 1.4674 + if type.isDate(): 1.4675 + assert not isEnforceRange and not isClamp 1.4676 + 1.4677 + declType = CGGeneric("Date") 1.4678 + if type.nullable(): 1.4679 + declType = CGTemplatedType("Nullable", declType) 1.4680 + dateVal = "${declName}.SetValue()" 1.4681 + else: 1.4682 + dateVal = "${declName}" 1.4683 + 1.4684 + if failureCode is None: 1.4685 + notDate = ('ThrowErrorMessage(cx, MSG_NOT_DATE, "%s");\n' 1.4686 + "%s" % (firstCap(sourceDescription), exceptionCode)) 1.4687 + else: 1.4688 + notDate = failureCode 1.4689 + 1.4690 + conversion = fill( 1.4691 + """ 1.4692 + JS::Rooted<JSObject*> possibleDateObject(cx, &$${val}.toObject()); 1.4693 + if (!JS_ObjectIsDate(cx, possibleDateObject) || 1.4694 + !${dateVal}.SetTimeStamp(cx, possibleDateObject)) { 1.4695 + $*{notDate} 1.4696 + } 1.4697 + """, 1.4698 + dateVal=dateVal, 1.4699 + notDate=notDate) 1.4700 + 1.4701 + conversion = wrapObjectTemplate(conversion, type, 1.4702 + "${declName}.SetNull();\n", notDate) 1.4703 + return JSToNativeConversionInfo(conversion, 1.4704 + declType=declType, 1.4705 + dealWithOptional=isOptional) 1.4706 + 1.4707 + if not type.isPrimitive(): 1.4708 + raise TypeError("Need conversion for argument type '%s'" % str(type)) 1.4709 + 1.4710 + typeName = builtinNames[type.tag()] 1.4711 + 1.4712 + conversionBehavior = "eDefault" 1.4713 + if isEnforceRange: 1.4714 + assert type.isInteger() 1.4715 + conversionBehavior = "eEnforceRange" 1.4716 + elif isClamp: 1.4717 + assert type.isInteger() 1.4718 + conversionBehavior = "eClamp" 1.4719 + 1.4720 + if type.nullable(): 1.4721 + declType = CGGeneric("Nullable<" + typeName + ">") 1.4722 + writeLoc = "${declName}.SetValue()" 1.4723 + readLoc = "${declName}.Value()" 1.4724 + nullCondition = "${val}.isNullOrUndefined()" 1.4725 + if defaultValue is not None and isinstance(defaultValue, IDLNullValue): 1.4726 + nullCondition = "!(${haveValue}) || " + nullCondition 1.4727 + template = ( 1.4728 + "if (%s) {\n" 1.4729 + " ${declName}.SetNull();\n" 1.4730 + "} else if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n" 1.4731 + "%s" 1.4732 + "}\n" % (nullCondition, typeName, conversionBehavior, 1.4733 + writeLoc, exceptionCodeIndented.define())) 1.4734 + else: 1.4735 + assert(defaultValue is None or 1.4736 + not isinstance(defaultValue, IDLNullValue)) 1.4737 + writeLoc = "${declName}" 1.4738 + readLoc = writeLoc 1.4739 + template = ( 1.4740 + "if (!ValueToPrimitive<%s, %s>(cx, ${val}, &%s)) {\n" 1.4741 + "%s" 1.4742 + "}\n" % (typeName, conversionBehavior, writeLoc, 1.4743 + exceptionCodeIndented.define())) 1.4744 + declType = CGGeneric(typeName) 1.4745 + 1.4746 + if type.isFloat() and not type.isUnrestricted(): 1.4747 + if lenientFloatCode is not None: 1.4748 + nonFiniteCode = lenientFloatCode 1.4749 + else: 1.4750 + nonFiniteCode = ('ThrowErrorMessage(cx, MSG_NOT_FINITE, "%s");\n' 1.4751 + "%s" % (firstCap(sourceDescription), exceptionCode)) 1.4752 + template = template.rstrip() 1.4753 + template += fill( 1.4754 + """ 1.4755 + else if (!mozilla::IsFinite(${readLoc})) { 1.4756 + // Note: mozilla::IsFinite will do the right thing 1.4757 + // when passed a non-finite float too. 1.4758 + $*{nonFiniteCode} 1.4759 + } 1.4760 + """, 1.4761 + readLoc=readLoc, 1.4762 + nonFiniteCode=nonFiniteCode) 1.4763 + 1.4764 + if (defaultValue is not None and 1.4765 + # We already handled IDLNullValue, so just deal with the other ones 1.4766 + not isinstance(defaultValue, IDLNullValue)): 1.4767 + tag = defaultValue.type.tag() 1.4768 + defaultStr = getHandleDefault(defaultValue) 1.4769 + template = CGIfElseWrapper( 1.4770 + "${haveValue}", 1.4771 + CGGeneric(template), 1.4772 + CGGeneric("%s = %s;\n" % (writeLoc, defaultStr))).define() 1.4773 + 1.4774 + return JSToNativeConversionInfo(template, declType=declType, 1.4775 + dealWithOptional=isOptional) 1.4776 + 1.4777 + 1.4778 +def instantiateJSToNativeConversion(info, replacements, checkForValue=False): 1.4779 + """ 1.4780 + Take a JSToNativeConversionInfo as returned by getJSToNativeConversionInfo 1.4781 + and a set of replacements as required by the strings in such an object, and 1.4782 + generate code to convert into stack C++ types. 1.4783 + 1.4784 + If checkForValue is True, then the conversion will get wrapped in 1.4785 + a check for ${haveValue}. 1.4786 + """ 1.4787 + templateBody, declType, holderType, dealWithOptional = ( 1.4788 + info.template, info.declType, info.holderType, info.dealWithOptional) 1.4789 + 1.4790 + if dealWithOptional and not checkForValue: 1.4791 + raise TypeError("Have to deal with optional things, but don't know how") 1.4792 + if checkForValue and declType is None: 1.4793 + raise TypeError("Need to predeclare optional things, so they will be " 1.4794 + "outside the check for big enough arg count!") 1.4795 + 1.4796 + # We can't precompute our holder constructor arguments, since 1.4797 + # those might depend on ${declName}, which we change below. Just 1.4798 + # compute arguments at the point when we need them as we go. 1.4799 + def getArgsCGThing(args): 1.4800 + return CGGeneric(string.Template(args).substitute(replacements)) 1.4801 + 1.4802 + result = CGList([]) 1.4803 + # Make a copy of "replacements" since we may be about to start modifying it 1.4804 + replacements = dict(replacements) 1.4805 + originalDeclName = replacements["declName"] 1.4806 + if declType is not None: 1.4807 + if dealWithOptional: 1.4808 + replacements["declName"] = "%s.Value()" % originalDeclName 1.4809 + declType = CGTemplatedType("Optional", declType) 1.4810 + declCtorArgs = None 1.4811 + elif info.declArgs is not None: 1.4812 + declCtorArgs = CGWrapper(getArgsCGThing(info.declArgs), 1.4813 + pre="(", post=")") 1.4814 + else: 1.4815 + declCtorArgs = None 1.4816 + result.append( 1.4817 + CGList([declType, CGGeneric(" "), 1.4818 + CGGeneric(originalDeclName), 1.4819 + declCtorArgs, CGGeneric(";\n")])) 1.4820 + 1.4821 + originalHolderName = replacements["holderName"] 1.4822 + if holderType is not None: 1.4823 + if dealWithOptional: 1.4824 + replacements["holderName"] = "%s.ref()" % originalHolderName 1.4825 + holderType = CGTemplatedType("Maybe", holderType) 1.4826 + holderCtorArgs = None 1.4827 + elif info.holderArgs is not None: 1.4828 + holderCtorArgs = CGWrapper(getArgsCGThing(info.holderArgs), 1.4829 + pre="(", post=")") 1.4830 + else: 1.4831 + holderCtorArgs = None 1.4832 + result.append( 1.4833 + CGList([holderType, CGGeneric(" "), 1.4834 + CGGeneric(originalHolderName), 1.4835 + holderCtorArgs, CGGeneric(";\n")])) 1.4836 + 1.4837 + conversion = CGGeneric( 1.4838 + string.Template(templateBody).substitute(replacements)) 1.4839 + 1.4840 + if checkForValue: 1.4841 + if dealWithOptional: 1.4842 + declConstruct = CGIndenter( 1.4843 + CGGeneric("%s.Construct(%s);\n" % 1.4844 + (originalDeclName, 1.4845 + getArgsCGThing(info.declArgs).define() if 1.4846 + info.declArgs else ""))) 1.4847 + if holderType is not None: 1.4848 + holderConstruct = CGIndenter( 1.4849 + CGGeneric("%s.construct(%s);\n" % 1.4850 + (originalHolderName, 1.4851 + getArgsCGThing(info.holderArgs).define() if 1.4852 + info.holderArgs else ""))) 1.4853 + else: 1.4854 + holderConstruct = None 1.4855 + else: 1.4856 + declConstruct = None 1.4857 + holderConstruct = None 1.4858 + 1.4859 + conversion = CGList([ 1.4860 + CGGeneric( 1.4861 + string.Template("if (${haveValue}) {\n").substitute(replacements)), 1.4862 + declConstruct, 1.4863 + holderConstruct, 1.4864 + CGIndenter(conversion), 1.4865 + CGGeneric("}\n") 1.4866 + ]) 1.4867 + 1.4868 + result.append(conversion) 1.4869 + return result 1.4870 + 1.4871 + 1.4872 +def convertConstIDLValueToJSVal(value): 1.4873 + if isinstance(value, IDLNullValue): 1.4874 + return "JS::NullValue()" 1.4875 + if isinstance(value, IDLUndefinedValue): 1.4876 + return "JS::UndefinedValue()" 1.4877 + tag = value.type.tag() 1.4878 + if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16, 1.4879 + IDLType.Tags.uint16, IDLType.Tags.int32]: 1.4880 + return "INT_TO_JSVAL(%s)" % (value.value) 1.4881 + if tag == IDLType.Tags.uint32: 1.4882 + return "UINT_TO_JSVAL(%sU)" % (value.value) 1.4883 + if tag in [IDLType.Tags.int64, IDLType.Tags.uint64]: 1.4884 + return "DOUBLE_TO_JSVAL(%s)" % numericValue(tag, value.value) 1.4885 + if tag == IDLType.Tags.bool: 1.4886 + return "JSVAL_TRUE" if value.value else "JSVAL_FALSE" 1.4887 + if tag in [IDLType.Tags.float, IDLType.Tags.double]: 1.4888 + return "DOUBLE_TO_JSVAL(%s)" % (value.value) 1.4889 + raise TypeError("Const value of unhandled type: %s" % value.type) 1.4890 + 1.4891 + 1.4892 +class CGArgumentConverter(CGThing): 1.4893 + """ 1.4894 + A class that takes an IDL argument object and its index in the 1.4895 + argument list and generates code to unwrap the argument to the 1.4896 + right native type. 1.4897 + 1.4898 + argDescription is a description of the argument for error-reporting 1.4899 + purposes. Callers should assume that it might get placed in the middle of a 1.4900 + sentence. If it ends up at the beginning of a sentence, its first character 1.4901 + will be automatically uppercased. 1.4902 + """ 1.4903 + def __init__(self, argument, index, descriptorProvider, 1.4904 + argDescription, 1.4905 + invalidEnumValueFatal=True, lenientFloatCode=None): 1.4906 + CGThing.__init__(self) 1.4907 + self.argument = argument 1.4908 + self.argDescription = argDescription 1.4909 + assert(not argument.defaultValue or argument.optional) 1.4910 + 1.4911 + replacer = { 1.4912 + "index": index, 1.4913 + "argc": "args.length()" 1.4914 + } 1.4915 + self.replacementVariables = { 1.4916 + "declName": "arg%d" % index, 1.4917 + "holderName": ("arg%d" % index) + "_holder", 1.4918 + "obj": "obj" 1.4919 + } 1.4920 + self.replacementVariables["val"] = string.Template( 1.4921 + "args[${index}]").substitute(replacer) 1.4922 + self.replacementVariables["mutableVal"] = self.replacementVariables["val"] 1.4923 + haveValueCheck = string.Template( 1.4924 + "args.hasDefined(${index})").substitute(replacer) 1.4925 + self.replacementVariables["haveValue"] = haveValueCheck 1.4926 + self.descriptorProvider = descriptorProvider 1.4927 + if self.argument.optional and not self.argument.defaultValue: 1.4928 + self.argcAndIndex = replacer 1.4929 + else: 1.4930 + self.argcAndIndex = None 1.4931 + self.invalidEnumValueFatal = invalidEnumValueFatal 1.4932 + self.lenientFloatCode = lenientFloatCode 1.4933 + 1.4934 + def define(self): 1.4935 + typeConversion = getJSToNativeConversionInfo( 1.4936 + self.argument.type, 1.4937 + self.descriptorProvider, 1.4938 + isOptional=(self.argcAndIndex is not None and 1.4939 + not self.argument.variadic), 1.4940 + invalidEnumValueFatal=self.invalidEnumValueFatal, 1.4941 + defaultValue=self.argument.defaultValue, 1.4942 + treatNullAs=self.argument.treatNullAs, 1.4943 + isEnforceRange=self.argument.enforceRange, 1.4944 + isClamp=self.argument.clamp, 1.4945 + lenientFloatCode=self.lenientFloatCode, 1.4946 + isMember="Variadic" if self.argument.variadic else False, 1.4947 + allowTreatNonCallableAsNull=self.argument.allowTreatNonCallableAsNull(), 1.4948 + sourceDescription=self.argDescription) 1.4949 + 1.4950 + if not self.argument.variadic: 1.4951 + return instantiateJSToNativeConversion( 1.4952 + typeConversion, 1.4953 + self.replacementVariables, 1.4954 + self.argcAndIndex is not None).define() 1.4955 + 1.4956 + # Variadic arguments get turned into a sequence. 1.4957 + if typeConversion.dealWithOptional: 1.4958 + raise TypeError("Shouldn't have optional things in variadics") 1.4959 + if typeConversion.holderType is not None: 1.4960 + raise TypeError("Shouldn't need holders for variadics") 1.4961 + 1.4962 + replacer = dict(self.argcAndIndex, **self.replacementVariables) 1.4963 + replacer["seqType"] = CGTemplatedType("binding_detail::AutoSequence", 1.4964 + typeConversion.declType).define() 1.4965 + if typeNeedsRooting(self.argument.type): 1.4966 + rooterDecl = ("SequenceRooter<%s> ${holderName}(cx, &${declName});\n" % 1.4967 + typeConversion.declType.define()) 1.4968 + else: 1.4969 + rooterDecl = "" 1.4970 + replacer["elemType"] = typeConversion.declType.define() 1.4971 + 1.4972 + # NOTE: Keep this in sync with sequence conversions as needed 1.4973 + variadicConversion = string.Template( 1.4974 + "${seqType} ${declName};\n" + 1.4975 + rooterDecl + 1.4976 + dedent(""" 1.4977 + if (${argc} > ${index}) { 1.4978 + if (!${declName}.SetCapacity(${argc} - ${index})) { 1.4979 + JS_ReportOutOfMemory(cx); 1.4980 + return false; 1.4981 + } 1.4982 + for (uint32_t variadicArg = ${index}; variadicArg < ${argc}; ++variadicArg) { 1.4983 + ${elemType}& slot = *${declName}.AppendElement(); 1.4984 + """) 1.4985 + ).substitute(replacer) 1.4986 + 1.4987 + val = string.Template("args[variadicArg]").substitute(replacer) 1.4988 + variadicConversion += indent( 1.4989 + string.Template(typeConversion.template).substitute({ 1.4990 + "val": val, 1.4991 + "mutableVal": val, 1.4992 + "declName": "slot", 1.4993 + # We only need holderName here to handle isExternal() 1.4994 + # interfaces, which use an internal holder for the 1.4995 + # conversion even when forceOwningType ends up true. 1.4996 + "holderName": "tempHolder", 1.4997 + # Use the same ${obj} as for the variadic arg itself 1.4998 + "obj": replacer["obj"] 1.4999 + }), 4) 1.5000 + 1.5001 + variadicConversion += (" }\n" 1.5002 + "}\n") 1.5003 + return variadicConversion 1.5004 + 1.5005 + 1.5006 +def getMaybeWrapValueFuncForType(type): 1.5007 + # Callbacks might actually be DOM objects; nothing prevents a page from 1.5008 + # doing that. 1.5009 + if type.isCallback() or type.isCallbackInterface() or type.isObject(): 1.5010 + if type.nullable(): 1.5011 + return "MaybeWrapObjectOrNullValue" 1.5012 + return "MaybeWrapObjectValue" 1.5013 + # Spidermonkey interfaces are never DOM objects. Neither are sequences or 1.5014 + # dictionaries, since those are always plain JS objects. 1.5015 + if type.isSpiderMonkeyInterface() or type.isDictionary() or type.isSequence(): 1.5016 + if type.nullable(): 1.5017 + return "MaybeWrapNonDOMObjectOrNullValue" 1.5018 + return "MaybeWrapNonDOMObjectValue" 1.5019 + if type.isAny(): 1.5020 + return "MaybeWrapValue" 1.5021 + 1.5022 + # For other types, just go ahead an fall back on MaybeWrapValue for now: 1.5023 + # it's always safe to do, and shouldn't be particularly slow for any of 1.5024 + # them 1.5025 + return "MaybeWrapValue" 1.5026 + 1.5027 + 1.5028 +sequenceWrapLevel = 0 1.5029 +mozMapWrapLevel = 0 1.5030 + 1.5031 + 1.5032 +def getWrapTemplateForType(type, descriptorProvider, result, successCode, 1.5033 + returnsNewObject, exceptionCode, typedArraysAreStructs): 1.5034 + """ 1.5035 + Reflect a C++ value stored in "result", of IDL type "type" into JS. The 1.5036 + "successCode" is the code to run once we have successfully done the 1.5037 + conversion and must guarantee that execution of the conversion template 1.5038 + stops once the successCode has executed (e.g. by doing a 'return', or by 1.5039 + doing a 'break' if the entire conversion template is inside a block that 1.5040 + the 'break' will exit). 1.5041 + 1.5042 + If typedArraysAreStructs is true, then if the type is a typed array, 1.5043 + "result" is one of the dom::TypedArray subclasses, not a JSObject*. 1.5044 + 1.5045 + The resulting string should be used with string.Template. It 1.5046 + needs the following keys when substituting: 1.5047 + 1.5048 + jsvalHandle: something that can be passed to methods taking a 1.5049 + JS::MutableHandle<JS::Value>. This can be a 1.5050 + JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*. 1.5051 + jsvalRef: something that can have .address() called on it to get a 1.5052 + JS::Value* and .set() called on it to set it to a JS::Value. 1.5053 + This can be a JS::MutableHandle<JS::Value> or a 1.5054 + JS::Rooted<JS::Value>. 1.5055 + obj: a JS::Handle<JSObject*>. 1.5056 + 1.5057 + Returns (templateString, infallibility of conversion template) 1.5058 + """ 1.5059 + if successCode is None: 1.5060 + successCode = "return true;\n" 1.5061 + 1.5062 + def setUndefined(): 1.5063 + return _setValue("", setter="setUndefined") 1.5064 + 1.5065 + def setNull(): 1.5066 + return _setValue("", setter="setNull") 1.5067 + 1.5068 + def setInt32(value): 1.5069 + return _setValue(value, setter="setInt32") 1.5070 + 1.5071 + def setString(value): 1.5072 + return _setValue(value, setter="setString") 1.5073 + 1.5074 + def setObject(value, wrapAsType=None): 1.5075 + return _setValue(value, wrapAsType=wrapAsType, setter="setObject") 1.5076 + 1.5077 + def setObjectOrNull(value, wrapAsType=None): 1.5078 + return _setValue(value, wrapAsType=wrapAsType, setter="setObjectOrNull") 1.5079 + 1.5080 + def setUint32(value): 1.5081 + return _setValue(value, setter="setNumber") 1.5082 + 1.5083 + def setDouble(value): 1.5084 + return _setValue("JS_NumberValue(%s)" % value) 1.5085 + 1.5086 + def setBoolean(value): 1.5087 + return _setValue(value, setter="setBoolean") 1.5088 + 1.5089 + def _setValue(value, wrapAsType=None, setter="set"): 1.5090 + """ 1.5091 + Returns the code to set the jsval to value. 1.5092 + 1.5093 + If wrapAsType is not None, then will wrap the resulting value using the 1.5094 + function that getMaybeWrapValueFuncForType(wrapAsType) returns. 1.5095 + Otherwise, no wrapping will be done. 1.5096 + """ 1.5097 + if wrapAsType is None: 1.5098 + tail = successCode 1.5099 + else: 1.5100 + tail = fill( 1.5101 + """ 1.5102 + if (!${maybeWrap}(cx, $${jsvalHandle})) { 1.5103 + $*{exceptionCode} 1.5104 + } 1.5105 + $*{successCode} 1.5106 + """, 1.5107 + maybeWrap=getMaybeWrapValueFuncForType(wrapAsType), 1.5108 + exceptionCode=exceptionCode, 1.5109 + successCode=successCode) 1.5110 + return ("${jsvalRef}.%s(%s);\n" % (setter, value)) + tail 1.5111 + 1.5112 + def wrapAndSetPtr(wrapCall, failureCode=None): 1.5113 + """ 1.5114 + Returns the code to set the jsval by calling "wrapCall". "failureCode" 1.5115 + is the code to run if calling "wrapCall" fails 1.5116 + """ 1.5117 + if failureCode is None: 1.5118 + failureCode = exceptionCode 1.5119 + return fill( 1.5120 + """ 1.5121 + if (!${wrapCall}) { 1.5122 + $*{failureCode} 1.5123 + } 1.5124 + $*{successCode} 1.5125 + """, 1.5126 + wrapCall=wrapCall, 1.5127 + failureCode=failureCode, 1.5128 + successCode=successCode) 1.5129 + 1.5130 + if type is None or type.isVoid(): 1.5131 + return (setUndefined(), True) 1.5132 + 1.5133 + if type.isArray(): 1.5134 + raise TypeError("Can't handle array return values yet") 1.5135 + 1.5136 + if (type.isSequence() or type.isMozMap()) and type.nullable(): 1.5137 + # These are both wrapped in Nullable<> 1.5138 + recTemplate, recInfall = getWrapTemplateForType(type.inner, descriptorProvider, 1.5139 + "%s.Value()" % result, successCode, 1.5140 + returnsNewObject, exceptionCode, 1.5141 + typedArraysAreStructs) 1.5142 + code = fill( 1.5143 + """ 1.5144 + 1.5145 + if (${result}.IsNull()) { 1.5146 + $*{setNull} 1.5147 + } 1.5148 + $*{recTemplate} 1.5149 + """, 1.5150 + result=result, 1.5151 + setNull=setNull(), 1.5152 + recTemplate=recTemplate) 1.5153 + return code, recInfall 1.5154 + 1.5155 + if type.isSequence(): 1.5156 + # Now do non-nullable sequences. Our success code is just to break to 1.5157 + # where we set the element in the array. Note that we bump the 1.5158 + # sequenceWrapLevel around this call so that nested sequence conversions 1.5159 + # will use different iteration variables. 1.5160 + global sequenceWrapLevel 1.5161 + index = "sequenceIdx%d" % sequenceWrapLevel 1.5162 + sequenceWrapLevel += 1 1.5163 + innerTemplate = wrapForType( 1.5164 + type.inner, descriptorProvider, 1.5165 + { 1.5166 + 'result': "%s[%s]" % (result, index), 1.5167 + 'successCode': "break;\n", 1.5168 + 'jsvalRef': "tmp", 1.5169 + 'jsvalHandle': "&tmp", 1.5170 + 'returnsNewObject': returnsNewObject, 1.5171 + 'exceptionCode': exceptionCode, 1.5172 + 'obj': "returnArray" 1.5173 + }) 1.5174 + sequenceWrapLevel -= 1 1.5175 + code = fill( 1.5176 + """ 1.5177 + 1.5178 + uint32_t length = ${result}.Length(); 1.5179 + JS::Rooted<JSObject*> returnArray(cx, JS_NewArrayObject(cx, length)); 1.5180 + if (!returnArray) { 1.5181 + $*{exceptionCode} 1.5182 + } 1.5183 + // Scope for 'tmp' 1.5184 + { 1.5185 + JS::Rooted<JS::Value> tmp(cx); 1.5186 + for (uint32_t ${index} = 0; ${index} < length; ++${index}) { 1.5187 + // Control block to let us common up the JS_DefineElement calls when there 1.5188 + // are different ways to succeed at wrapping the object. 1.5189 + do { 1.5190 + $*{innerTemplate} 1.5191 + } while (0); 1.5192 + if (!JS_DefineElement(cx, returnArray, ${index}, tmp, 1.5193 + nullptr, nullptr, JSPROP_ENUMERATE)) { 1.5194 + $*{exceptionCode} 1.5195 + } 1.5196 + } 1.5197 + } 1.5198 + $*{set} 1.5199 + """, 1.5200 + result=result, 1.5201 + exceptionCode=exceptionCode, 1.5202 + index=index, 1.5203 + innerTemplate=innerTemplate, 1.5204 + set=setObject("*returnArray")) 1.5205 + 1.5206 + return (code, False) 1.5207 + 1.5208 + if type.isMozMap(): 1.5209 + # Now do non-nullable MozMap. Our success code is just to break to 1.5210 + # where we define the property on the object. Note that we bump the 1.5211 + # mozMapWrapLevel around this call so that nested MozMap conversions 1.5212 + # will use different temp value names. 1.5213 + global mozMapWrapLevel 1.5214 + valueName = "mozMapValue%d" % mozMapWrapLevel 1.5215 + mozMapWrapLevel += 1 1.5216 + innerTemplate = wrapForType( 1.5217 + type.inner, descriptorProvider, 1.5218 + { 1.5219 + 'result': valueName, 1.5220 + 'successCode': "break;\n", 1.5221 + 'jsvalRef': "tmp", 1.5222 + 'jsvalHandle': "&tmp", 1.5223 + 'returnsNewObject': returnsNewObject, 1.5224 + 'exceptionCode': exceptionCode, 1.5225 + 'obj': "returnObj" 1.5226 + }) 1.5227 + mozMapWrapLevel -= 1 1.5228 + code = fill( 1.5229 + """ 1.5230 + 1.5231 + nsTArray<nsString> keys; 1.5232 + ${result}.GetKeys(keys); 1.5233 + JS::Rooted<JSObject*> returnObj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); 1.5234 + if (!returnObj) { 1.5235 + $*{exceptionCode} 1.5236 + } 1.5237 + // Scope for 'tmp' 1.5238 + { 1.5239 + JS::Rooted<JS::Value> tmp(cx); 1.5240 + for (size_t idx = 0; idx < keys.Length(); ++idx) { 1.5241 + auto& ${valueName} = ${result}.Get(keys[idx]); 1.5242 + // Control block to let us common up the JS_DefineUCProperty calls when there 1.5243 + // are different ways to succeed at wrapping the value. 1.5244 + do { 1.5245 + $*{innerTemplate} 1.5246 + } while (0); 1.5247 + if (!JS_DefineUCProperty(cx, returnObj, keys[idx].get(), 1.5248 + keys[idx].Length(), tmp, 1.5249 + JS_PropertyStub, JS_StrictPropertyStub, 1.5250 + JSPROP_ENUMERATE)) { 1.5251 + $*{exceptionCode} 1.5252 + } 1.5253 + } 1.5254 + } 1.5255 + $*{set} 1.5256 + """, 1.5257 + result=result, 1.5258 + exceptionCode=exceptionCode, 1.5259 + valueName=valueName, 1.5260 + innerTemplate=innerTemplate, 1.5261 + set=setObject("*returnObj")) 1.5262 + 1.5263 + return (code, False) 1.5264 + 1.5265 + if type.isGeckoInterface() and not type.isCallbackInterface(): 1.5266 + descriptor = descriptorProvider.getDescriptor(type.unroll().inner.identifier.name) 1.5267 + if type.nullable(): 1.5268 + wrappingCode = ("if (!%s) {\n" % (result) + 1.5269 + indent(setNull()) + 1.5270 + "}\n") 1.5271 + else: 1.5272 + wrappingCode = "" 1.5273 + 1.5274 + if not descriptor.interface.isExternal() and not descriptor.skipGen: 1.5275 + if descriptor.wrapperCache: 1.5276 + assert descriptor.nativeOwnership != 'owned' 1.5277 + wrapMethod = "WrapNewBindingObject" 1.5278 + else: 1.5279 + if not returnsNewObject: 1.5280 + raise MethodNotNewObjectError(descriptor.interface.identifier.name) 1.5281 + if descriptor.nativeOwnership == 'owned': 1.5282 + wrapMethod = "WrapNewBindingNonWrapperCachedOwnedObject" 1.5283 + else: 1.5284 + wrapMethod = "WrapNewBindingNonWrapperCachedObject" 1.5285 + wrap = "%s(cx, ${obj}, %s, ${jsvalHandle})" % (wrapMethod, result) 1.5286 + if not descriptor.hasXPConnectImpls: 1.5287 + # Can only fail to wrap as a new-binding object 1.5288 + # if they already threw an exception. 1.5289 + #XXX Assertion disabled for now, see bug 991271. 1.5290 + failed = ("MOZ_ASSERT(true || JS_IsExceptionPending(cx));\n" + 1.5291 + exceptionCode) 1.5292 + else: 1.5293 + if descriptor.notflattened: 1.5294 + raise TypeError("%s has XPConnect impls but not flattened; " 1.5295 + "fallback won't work correctly" % 1.5296 + descriptor.interface.identifier.name) 1.5297 + # Try old-style wrapping for bindings which might be XPConnect impls. 1.5298 + failed = wrapAndSetPtr("HandleNewBindingWrappingFailure(cx, ${obj}, %s, ${jsvalHandle})" % result) 1.5299 + else: 1.5300 + if descriptor.notflattened: 1.5301 + getIID = "&NS_GET_IID(%s), " % descriptor.nativeType 1.5302 + else: 1.5303 + getIID = "" 1.5304 + wrap = "WrapObject(cx, %s, %s${jsvalHandle})" % (result, getIID) 1.5305 + failed = None 1.5306 + 1.5307 + wrappingCode += wrapAndSetPtr(wrap, failed) 1.5308 + return (wrappingCode, False) 1.5309 + 1.5310 + if type.isDOMString(): 1.5311 + if type.nullable(): 1.5312 + return (wrapAndSetPtr("xpc::StringToJsval(cx, %s, ${jsvalHandle})" % result), False) 1.5313 + else: 1.5314 + return (wrapAndSetPtr("xpc::NonVoidStringToJsval(cx, %s, ${jsvalHandle})" % result), False) 1.5315 + 1.5316 + if type.isByteString(): 1.5317 + if type.nullable(): 1.5318 + return (wrapAndSetPtr("ByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False) 1.5319 + else: 1.5320 + return (wrapAndSetPtr("NonVoidByteStringToJsval(cx, %s, ${jsvalHandle})" % result), False) 1.5321 + 1.5322 + if type.isEnum(): 1.5323 + if type.nullable(): 1.5324 + resultLoc = "%s.Value()" % result 1.5325 + else: 1.5326 + resultLoc = result 1.5327 + conversion = fill( 1.5328 + """ 1.5329 + { 1.5330 + // Scope for resultStr 1.5331 + MOZ_ASSERT(uint32_t(${result}) < ArrayLength(${strings})); 1.5332 + JSString* resultStr = JS_NewStringCopyN(cx, ${strings}[uint32_t(${result})].value, ${strings}[uint32_t(${result})].length); 1.5333 + if (!resultStr) { 1.5334 + $*{exceptionCode} 1.5335 + } 1.5336 + $*{setResultStr} 1.5337 + } 1.5338 + """, 1.5339 + result=resultLoc, 1.5340 + strings=(type.unroll().inner.identifier.name + "Values::" + 1.5341 + ENUM_ENTRY_VARIABLE_NAME), 1.5342 + exceptionCode=exceptionCode, 1.5343 + setResultStr=setString("resultStr")) 1.5344 + 1.5345 + if type.nullable(): 1.5346 + conversion = CGIfElseWrapper( 1.5347 + "%s.IsNull()" % result, 1.5348 + CGGeneric(setNull()), 1.5349 + CGGeneric(conversion)).define() 1.5350 + return conversion, False 1.5351 + 1.5352 + if type.isCallback() or type.isCallbackInterface(): 1.5353 + wrapCode = setObject( 1.5354 + "*GetCallbackFromCallbackObject(%(result)s)", 1.5355 + wrapAsType=type) 1.5356 + if type.nullable(): 1.5357 + wrapCode = ( 1.5358 + "if (%(result)s) {\n" + 1.5359 + indent(wrapCode) + 1.5360 + "} else {\n" + 1.5361 + indent(setNull()) + 1.5362 + "}\n") 1.5363 + wrapCode = wrapCode % {"result": result} 1.5364 + return wrapCode, False 1.5365 + 1.5366 + if type.isAny(): 1.5367 + # See comments in WrapNewBindingObject explaining why we need 1.5368 + # to wrap here. 1.5369 + # NB: _setValue(..., type-that-is-any) calls JS_WrapValue(), so is fallible 1.5370 + return (_setValue(result, wrapAsType=type), False) 1.5371 + 1.5372 + if (type.isObject() or (type.isSpiderMonkeyInterface() and 1.5373 + not typedArraysAreStructs)): 1.5374 + # See comments in WrapNewBindingObject explaining why we need 1.5375 + # to wrap here. 1.5376 + if type.nullable(): 1.5377 + toValue = "%s" 1.5378 + setter = setObjectOrNull 1.5379 + else: 1.5380 + toValue = "*%s" 1.5381 + setter = setObject 1.5382 + # NB: setObject{,OrNull}(..., some-object-type) calls JS_WrapValue(), so is fallible 1.5383 + return (setter(toValue % result, wrapAsType=type), False) 1.5384 + 1.5385 + if not (type.isUnion() or type.isPrimitive() or type.isDictionary() or 1.5386 + type.isDate() or 1.5387 + (type.isSpiderMonkeyInterface() and typedArraysAreStructs)): 1.5388 + raise TypeError("Need to learn to wrap %s" % type) 1.5389 + 1.5390 + if type.nullable(): 1.5391 + recTemplate, recInfal = getWrapTemplateForType(type.inner, descriptorProvider, 1.5392 + "%s.Value()" % result, successCode, 1.5393 + returnsNewObject, exceptionCode, 1.5394 + typedArraysAreStructs) 1.5395 + return ("if (%s.IsNull()) {\n" % result + 1.5396 + indent(setNull()) + 1.5397 + "}\n" + 1.5398 + recTemplate, recInfal) 1.5399 + 1.5400 + if type.isSpiderMonkeyInterface(): 1.5401 + assert typedArraysAreStructs 1.5402 + # See comments in WrapNewBindingObject explaining why we need 1.5403 + # to wrap here. 1.5404 + # NB: setObject(..., some-object-type) calls JS_WrapValue(), so is fallible 1.5405 + return (setObject("*%s.Obj()" % result, 1.5406 + wrapAsType=type), False) 1.5407 + 1.5408 + if type.isUnion(): 1.5409 + return (wrapAndSetPtr("%s.ToJSVal(cx, ${obj}, ${jsvalHandle})" % result), 1.5410 + False) 1.5411 + 1.5412 + if type.isDictionary(): 1.5413 + return (wrapAndSetPtr("%s.ToObject(cx, ${jsvalHandle})" % result), 1.5414 + False) 1.5415 + 1.5416 + if type.isDate(): 1.5417 + return (wrapAndSetPtr("%s.ToDateObject(cx, ${jsvalHandle})" % result), 1.5418 + False) 1.5419 + 1.5420 + tag = type.tag() 1.5421 + 1.5422 + if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, IDLType.Tags.int16, 1.5423 + IDLType.Tags.uint16, IDLType.Tags.int32]: 1.5424 + return (setInt32("int32_t(%s)" % result), True) 1.5425 + 1.5426 + elif tag in [IDLType.Tags.int64, IDLType.Tags.uint64, 1.5427 + IDLType.Tags.unrestricted_float, IDLType.Tags.float, 1.5428 + IDLType.Tags.unrestricted_double, IDLType.Tags.double]: 1.5429 + # XXXbz will cast to double do the "even significand" thing that webidl 1.5430 + # calls for for 64-bit ints? Do we care? 1.5431 + return (setDouble("double(%s)" % result), True) 1.5432 + 1.5433 + elif tag == IDLType.Tags.uint32: 1.5434 + return (setUint32(result), True) 1.5435 + 1.5436 + elif tag == IDLType.Tags.bool: 1.5437 + return (setBoolean(result), True) 1.5438 + 1.5439 + else: 1.5440 + raise TypeError("Need to learn to wrap primitive: %s" % type) 1.5441 + 1.5442 + 1.5443 +def wrapForType(type, descriptorProvider, templateValues): 1.5444 + """ 1.5445 + Reflect a C++ value of IDL type "type" into JS. TemplateValues is a dict 1.5446 + that should contain: 1.5447 + 1.5448 + * 'jsvalRef': something that can have .address() called on it to get a 1.5449 + JS::Value* and .set() called on it to set it to a JS::Value. 1.5450 + This can be a JS::MutableHandle<JS::Value> or a 1.5451 + JS::Rooted<JS::Value>. 1.5452 + * 'jsvalHandle': something that can be passed to methods taking a 1.5453 + JS::MutableHandle<JS::Value>. This can be a 1.5454 + JS::MutableHandle<JS::Value> or a JS::Rooted<JS::Value>*. 1.5455 + * 'obj' (optional): the name of the variable that contains the JSObject to 1.5456 + use as a scope when wrapping, if not supplied 'obj' 1.5457 + will be used as the name 1.5458 + * 'result' (optional): the name of the variable in which the C++ value is 1.5459 + stored, if not supplied 'result' will be used as 1.5460 + the name 1.5461 + * 'successCode' (optional): the code to run once we have successfully 1.5462 + done the conversion, if not supplied 'return 1.5463 + true;' will be used as the code. The 1.5464 + successCode must ensure that once it runs no 1.5465 + more of the conversion template will be 1.5466 + executed (e.g. by doing a 'return' or 'break' 1.5467 + as appropriate). 1.5468 + * 'returnsNewObject' (optional): If true, we're wrapping for the return 1.5469 + value of a [NewObject] method. Assumed 1.5470 + false if not set. 1.5471 + * 'exceptionCode' (optional): Code to run when a JS exception is thrown. 1.5472 + The default is "return false;". The code 1.5473 + passed here must return. 1.5474 + """ 1.5475 + wrap = getWrapTemplateForType(type, descriptorProvider, 1.5476 + templateValues.get('result', 'result'), 1.5477 + templateValues.get('successCode', None), 1.5478 + templateValues.get('returnsNewObject', False), 1.5479 + templateValues.get('exceptionCode', 1.5480 + "return false;\n"), 1.5481 + templateValues.get('typedArraysAreStructs', 1.5482 + False))[0] 1.5483 + 1.5484 + defaultValues = {'obj': 'obj'} 1.5485 + return string.Template(wrap).substitute(defaultValues, **templateValues) 1.5486 + 1.5487 + 1.5488 +def infallibleForMember(member, type, descriptorProvider): 1.5489 + """ 1.5490 + Determine the fallibility of changing a C++ value of IDL type "type" into 1.5491 + JS for the given attribute. Apart from returnsNewObject, all the defaults 1.5492 + are used, since the fallbility does not change based on the boolean values, 1.5493 + and the template will be discarded. 1.5494 + 1.5495 + CURRENT ASSUMPTIONS: 1.5496 + We assume that successCode for wrapping up return values cannot contain 1.5497 + failure conditions. 1.5498 + """ 1.5499 + return getWrapTemplateForType(type, descriptorProvider, 'result', None, 1.5500 + memberReturnsNewObject(member), "return false;\n", 1.5501 + False)[1] 1.5502 + 1.5503 + 1.5504 +def leafTypeNeedsCx(type, retVal): 1.5505 + return (type.isAny() or type.isObject() or 1.5506 + (retVal and type.isSpiderMonkeyInterface())) 1.5507 + 1.5508 + 1.5509 +def leafTypeNeedsScopeObject(type, retVal): 1.5510 + return retVal and type.isSpiderMonkeyInterface() 1.5511 + 1.5512 + 1.5513 +def leafTypeNeedsRooting(type): 1.5514 + return leafTypeNeedsCx(type, False) or type.isSpiderMonkeyInterface() 1.5515 + 1.5516 + 1.5517 +def typeNeedsRooting(type): 1.5518 + return typeMatchesLambda(type, 1.5519 + lambda t: leafTypeNeedsRooting(t)) 1.5520 + 1.5521 + 1.5522 +def typeNeedsCx(type, retVal=False): 1.5523 + return typeMatchesLambda(type, 1.5524 + lambda t: leafTypeNeedsCx(t, retVal)) 1.5525 + 1.5526 + 1.5527 +def typeNeedsScopeObject(type, retVal=False): 1.5528 + return typeMatchesLambda(type, 1.5529 + lambda t: leafTypeNeedsScopeObject(t, retVal)) 1.5530 + 1.5531 + 1.5532 +def typeMatchesLambda(type, func): 1.5533 + if type is None: 1.5534 + return False 1.5535 + if type.nullable(): 1.5536 + return typeMatchesLambda(type.inner, func) 1.5537 + if type.isSequence() or type.isMozMap() or type.isArray(): 1.5538 + return typeMatchesLambda(type.inner, func) 1.5539 + if type.isUnion(): 1.5540 + return any(typeMatchesLambda(t, func) for t in 1.5541 + type.unroll().flatMemberTypes) 1.5542 + if type.isDictionary(): 1.5543 + return dictionaryMatchesLambda(type.inner, func) 1.5544 + return func(type) 1.5545 + 1.5546 + 1.5547 +def dictionaryMatchesLambda(dictionary, func): 1.5548 + return (any(typeMatchesLambda(m.type, func) for m in dictionary.members) or 1.5549 + (dictionary.parent and dictionaryMatchesLambda(dictionary.parent, func))) 1.5550 + 1.5551 + 1.5552 +# Whenever this is modified, please update CGNativeMember.getRetvalInfo as 1.5553 +# needed to keep the types compatible. 1.5554 +def getRetvalDeclarationForType(returnType, descriptorProvider, 1.5555 + resultAlreadyAddRefed, 1.5556 + isMember=False): 1.5557 + """ 1.5558 + Returns a tuple containing four things: 1.5559 + 1.5560 + 1) A CGThing for the type of the return value, or None if there is no need 1.5561 + for a return value. 1.5562 + 1.5563 + 2) A value indicating the kind of ourparam to pass the value as. Valid 1.5564 + options are None to not pass as an out param at all, "ref" (to pass a 1.5565 + reference as an out param), and "ptr" (to pass a pointer as an out 1.5566 + param). 1.5567 + 1.5568 + 3) A CGThing for a tracer for the return value, or None if no tracing is 1.5569 + needed. 1.5570 + 1.5571 + 4) An argument string to pass to the retval declaration 1.5572 + constructor or None if there are no arguments. 1.5573 + """ 1.5574 + if returnType is None or returnType.isVoid(): 1.5575 + # Nothing to declare 1.5576 + return None, None, None, None 1.5577 + if returnType.isPrimitive() and returnType.tag() in builtinNames: 1.5578 + result = CGGeneric(builtinNames[returnType.tag()]) 1.5579 + if returnType.nullable(): 1.5580 + result = CGTemplatedType("Nullable", result) 1.5581 + return result, None, None, None 1.5582 + if returnType.isDOMString(): 1.5583 + if isMember: 1.5584 + return CGGeneric("nsString"), "ref", None, None 1.5585 + return CGGeneric("DOMString"), "ref", None, None 1.5586 + if returnType.isByteString(): 1.5587 + return CGGeneric("nsCString"), "ref", None, None 1.5588 + if returnType.isEnum(): 1.5589 + result = CGGeneric(returnType.unroll().inner.identifier.name) 1.5590 + if returnType.nullable(): 1.5591 + result = CGTemplatedType("Nullable", result) 1.5592 + return result, None, None, None 1.5593 + if returnType.isGeckoInterface(): 1.5594 + result = CGGeneric(descriptorProvider.getDescriptor( 1.5595 + returnType.unroll().inner.identifier.name).nativeType) 1.5596 + if descriptorProvider.getDescriptor( 1.5597 + returnType.unroll().inner.identifier.name).nativeOwnership == 'owned': 1.5598 + result = CGTemplatedType("nsAutoPtr", result) 1.5599 + elif resultAlreadyAddRefed: 1.5600 + result = CGTemplatedType("nsRefPtr", result) 1.5601 + else: 1.5602 + result = CGWrapper(result, post="*") 1.5603 + return result, None, None, None 1.5604 + if returnType.isCallback(): 1.5605 + name = returnType.unroll().identifier.name 1.5606 + return CGGeneric("nsRefPtr<%s>" % name), None, None, None 1.5607 + if returnType.isAny(): 1.5608 + if isMember: 1.5609 + return CGGeneric("JS::Value"), None, None, None 1.5610 + return CGGeneric("JS::Rooted<JS::Value>"), "ptr", None, "cx" 1.5611 + if returnType.isObject() or returnType.isSpiderMonkeyInterface(): 1.5612 + if isMember: 1.5613 + return CGGeneric("JSObject*"), None, None, None 1.5614 + return CGGeneric("JS::Rooted<JSObject*>"), "ptr", None, "cx" 1.5615 + if returnType.isSequence(): 1.5616 + nullable = returnType.nullable() 1.5617 + if nullable: 1.5618 + returnType = returnType.inner 1.5619 + # If our result is already addrefed, use the right type in the 1.5620 + # sequence argument here. 1.5621 + result, _, _, _ = getRetvalDeclarationForType(returnType.inner, 1.5622 + descriptorProvider, 1.5623 + resultAlreadyAddRefed, 1.5624 + isMember="Sequence") 1.5625 + # While we have our inner type, set up our rooter, if needed 1.5626 + if not isMember and typeNeedsRooting(returnType): 1.5627 + rooter = CGGeneric("SequenceRooter<%s > resultRooter(cx, &result);\n" % 1.5628 + result.define()) 1.5629 + else: 1.5630 + rooter = None 1.5631 + result = CGTemplatedType("nsTArray", result) 1.5632 + if nullable: 1.5633 + result = CGTemplatedType("Nullable", result) 1.5634 + return result, "ref", rooter, None 1.5635 + if returnType.isMozMap(): 1.5636 + nullable = returnType.nullable() 1.5637 + if nullable: 1.5638 + returnType = returnType.inner 1.5639 + # If our result is already addrefed, use the right type in the 1.5640 + # MozMap argument here. 1.5641 + result, _, _, _ = getRetvalDeclarationForType(returnType.inner, 1.5642 + descriptorProvider, 1.5643 + resultAlreadyAddRefed, 1.5644 + isMember="MozMap") 1.5645 + # While we have our inner type, set up our rooter, if needed 1.5646 + if not isMember and typeNeedsRooting(returnType): 1.5647 + rooter = CGGeneric("MozMapRooter<%s> resultRooter(cx, &result);\n" % 1.5648 + result.define()) 1.5649 + else: 1.5650 + rooter = None 1.5651 + result = CGTemplatedType("MozMap", result) 1.5652 + if nullable: 1.5653 + result = CGTemplatedType("Nullable", result) 1.5654 + return result, "ref", rooter, None 1.5655 + if returnType.isDictionary(): 1.5656 + nullable = returnType.nullable() 1.5657 + dictName = CGDictionary.makeDictionaryName(returnType.unroll().inner) 1.5658 + result = CGGeneric(dictName) 1.5659 + if not isMember and typeNeedsRooting(returnType): 1.5660 + if nullable: 1.5661 + result = CGTemplatedType("NullableRootedDictionary", result) 1.5662 + else: 1.5663 + result = CGTemplatedType("RootedDictionary", result) 1.5664 + resultArgs = "cx" 1.5665 + else: 1.5666 + if nullable: 1.5667 + result = CGTemplatedType("Nullable", result) 1.5668 + resultArgs = None 1.5669 + return result, "ref", None, resultArgs 1.5670 + if returnType.isUnion(): 1.5671 + result = CGGeneric(CGUnionStruct.unionTypeName(returnType.unroll(), True)) 1.5672 + if not isMember and typeNeedsRooting(returnType): 1.5673 + if returnType.nullable(): 1.5674 + result = CGTemplatedType("NullableRootedUnion", result) 1.5675 + else: 1.5676 + result = CGTemplatedType("RootedUnion", result) 1.5677 + resultArgs = "cx" 1.5678 + else: 1.5679 + if returnType.nullable(): 1.5680 + result = CGTemplatedType("Nullable", result) 1.5681 + resultArgs = None 1.5682 + return result, "ref", None, resultArgs 1.5683 + if returnType.isDate(): 1.5684 + result = CGGeneric("Date") 1.5685 + if returnType.nullable(): 1.5686 + result = CGTemplatedType("Nullable", result) 1.5687 + return result, None, None, None 1.5688 + raise TypeError("Don't know how to declare return value for %s" % 1.5689 + returnType) 1.5690 + 1.5691 + 1.5692 +def isResultAlreadyAddRefed(extendedAttributes): 1.5693 + return 'resultNotAddRefed' not in extendedAttributes 1.5694 + 1.5695 + 1.5696 +def needCx(returnType, arguments, extendedAttributes, considerTypes): 1.5697 + return (considerTypes and 1.5698 + (typeNeedsCx(returnType, True) or 1.5699 + any(typeNeedsCx(a.type) for a in arguments)) or 1.5700 + 'implicitJSContext' in extendedAttributes) 1.5701 + 1.5702 + 1.5703 +def needScopeObject(returnType, arguments, extendedAttributes, 1.5704 + isWrapperCached, considerTypes, isMember): 1.5705 + """ 1.5706 + isMember should be true if we're dealing with an attribute 1.5707 + annotated as [StoreInSlot]. 1.5708 + """ 1.5709 + return (considerTypes and not isWrapperCached and 1.5710 + ((not isMember and typeNeedsScopeObject(returnType, True)) or 1.5711 + any(typeNeedsScopeObject(a.type) for a in arguments))) 1.5712 + 1.5713 + 1.5714 +class CGCallGenerator(CGThing): 1.5715 + """ 1.5716 + A class to generate an actual call to a C++ object. Assumes that the C++ 1.5717 + object is stored in a variable whose name is given by the |object| argument. 1.5718 + 1.5719 + errorReport should be a CGThing for an error report or None if no 1.5720 + error reporting is needed. 1.5721 + """ 1.5722 + def __init__(self, errorReport, arguments, argsPre, returnType, 1.5723 + extendedAttributes, descriptorProvider, nativeMethodName, 1.5724 + static, object="self", argsPost=[]): 1.5725 + CGThing.__init__(self) 1.5726 + 1.5727 + assert errorReport is None or isinstance(errorReport, CGThing) 1.5728 + 1.5729 + isFallible = errorReport is not None 1.5730 + 1.5731 + resultAlreadyAddRefed = isResultAlreadyAddRefed(extendedAttributes) 1.5732 + result, resultOutParam, resultRooter, resultArgs = \ 1.5733 + getRetvalDeclarationForType( 1.5734 + returnType, descriptorProvider, resultAlreadyAddRefed) 1.5735 + 1.5736 + args = CGList([CGGeneric(arg) for arg in argsPre], ", ") 1.5737 + for a, name in arguments: 1.5738 + arg = CGGeneric(name) 1.5739 + 1.5740 + # Now constify the things that need it 1.5741 + def needsConst(a): 1.5742 + if a.type.isDictionary(): 1.5743 + return True 1.5744 + if a.type.isSequence(): 1.5745 + return True 1.5746 + if a.type.isMozMap(): 1.5747 + return True 1.5748 + # isObject() types are always a JS::Rooted, whether 1.5749 + # nullable or not, and it turns out a const JS::Rooted 1.5750 + # is not very helpful at all (in particular, it won't 1.5751 + # even convert to a JS::Handle). 1.5752 + # XXX bz Well, why not??? 1.5753 + if a.type.nullable() and not a.type.isObject(): 1.5754 + return True 1.5755 + if a.type.isString(): 1.5756 + return True 1.5757 + if a.optional and not a.defaultValue: 1.5758 + # If a.defaultValue, then it's not going to use an Optional, 1.5759 + # so doesn't need to be const just due to being optional. 1.5760 + # This also covers variadic arguments. 1.5761 + return True 1.5762 + if a.type.isUnion(): 1.5763 + return True 1.5764 + if a.type.isSpiderMonkeyInterface(): 1.5765 + return True 1.5766 + return False 1.5767 + if needsConst(a): 1.5768 + arg = CGWrapper(arg, pre="Constify(", post=")") 1.5769 + # And convert NonNull<T> to T& 1.5770 + if (((a.type.isGeckoInterface() or a.type.isCallback()) and not a.type.nullable()) or 1.5771 + a.type.isDOMString()): 1.5772 + arg = CGWrapper(arg, pre="NonNullHelper(", post=")") 1.5773 + args.append(arg) 1.5774 + 1.5775 + # Return values that go in outparams go here 1.5776 + if resultOutParam is not None: 1.5777 + if resultOutParam is "ref": 1.5778 + args.append(CGGeneric("result")) 1.5779 + else: 1.5780 + assert resultOutParam is "ptr" 1.5781 + args.append(CGGeneric("&result")) 1.5782 + 1.5783 + if isFallible: 1.5784 + args.append(CGGeneric("rv")) 1.5785 + args.extend(CGGeneric(arg) for arg in argsPost) 1.5786 + 1.5787 + # Build up our actual call 1.5788 + self.cgRoot = CGList([]) 1.5789 + 1.5790 + call = CGGeneric(nativeMethodName) 1.5791 + if not static: 1.5792 + call = CGWrapper(call, pre="%s->" % object) 1.5793 + call = CGList([call, CGWrapper(args, pre="(", post=");\n")]) 1.5794 + if result is not None: 1.5795 + if resultRooter is not None: 1.5796 + self.cgRoot.prepend(resultRooter) 1.5797 + if resultArgs is not None: 1.5798 + resultArgs = "(%s)" % resultArgs 1.5799 + else: 1.5800 + resultArgs = "" 1.5801 + result = CGWrapper(result, post=(" result%s;\n" % resultArgs)) 1.5802 + self.cgRoot.prepend(result) 1.5803 + if not resultOutParam: 1.5804 + call = CGWrapper(call, pre="result = ") 1.5805 + 1.5806 + call = CGWrapper(call) 1.5807 + self.cgRoot.append(call) 1.5808 + 1.5809 + if isFallible: 1.5810 + self.cgRoot.prepend(CGGeneric("ErrorResult rv;\n")) 1.5811 + self.cgRoot.append(CGGeneric("rv.WouldReportJSException();\n")) 1.5812 + self.cgRoot.append(CGGeneric("if (rv.Failed()) {\n")) 1.5813 + self.cgRoot.append(CGIndenter(errorReport)) 1.5814 + self.cgRoot.append(CGGeneric("}\n")) 1.5815 + 1.5816 + def define(self): 1.5817 + return self.cgRoot.define() 1.5818 + 1.5819 + 1.5820 +def getUnionMemberName(type): 1.5821 + if type.isGeckoInterface(): 1.5822 + return type.inner.identifier.name 1.5823 + if type.isEnum(): 1.5824 + return type.inner.identifier.name 1.5825 + if type.isArray() or type.isSequence(): 1.5826 + return str(type) 1.5827 + return type.name 1.5828 + 1.5829 + 1.5830 +class MethodNotNewObjectError(Exception): 1.5831 + def __init__(self, typename): 1.5832 + self.typename = typename 1.5833 + 1.5834 +# A counter for making sure that when we're wrapping up things in 1.5835 +# nested sequences we don't use the same variable name to iterate over 1.5836 +# different sequences. 1.5837 +sequenceWrapLevel = 0 1.5838 + 1.5839 + 1.5840 +def wrapTypeIntoCurrentCompartment(type, value, isMember=True): 1.5841 + """ 1.5842 + Take the thing named by "value" and if it contains "any", 1.5843 + "object", or spidermonkey-interface types inside return a CGThing 1.5844 + that will wrap them into the current compartment. 1.5845 + """ 1.5846 + if type.isAny(): 1.5847 + assert not type.nullable() 1.5848 + if isMember: 1.5849 + value = "JS::MutableHandle<JS::Value>::fromMarkedLocation(&%s)" % value 1.5850 + else: 1.5851 + value = "&" + value 1.5852 + return CGGeneric("if (!JS_WrapValue(cx, %s)) {\n" 1.5853 + " return false;\n" 1.5854 + "}\n" % value) 1.5855 + 1.5856 + if type.isObject(): 1.5857 + if isMember: 1.5858 + value = "JS::MutableHandle<JSObject*>::fromMarkedLocation(&%s)" % value 1.5859 + else: 1.5860 + value = "&" + value 1.5861 + return CGGeneric("if (!JS_WrapObject(cx, %s)) {\n" 1.5862 + " return false;\n" 1.5863 + "}\n" % value) 1.5864 + 1.5865 + if type.isSpiderMonkeyInterface(): 1.5866 + origValue = value 1.5867 + if type.nullable(): 1.5868 + value = "%s.Value()" % value 1.5869 + wrapCode = CGGeneric("if (!%s.WrapIntoNewCompartment(cx)) {\n" 1.5870 + " return false;\n" 1.5871 + "}\n" % value) 1.5872 + if type.nullable(): 1.5873 + wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue) 1.5874 + return wrapCode 1.5875 + 1.5876 + if type.isSequence(): 1.5877 + origValue = value 1.5878 + origType = type 1.5879 + if type.nullable(): 1.5880 + type = type.inner 1.5881 + value = "%s.Value()" % value 1.5882 + global sequenceWrapLevel 1.5883 + index = "indexName%d" % sequenceWrapLevel 1.5884 + sequenceWrapLevel += 1 1.5885 + wrapElement = wrapTypeIntoCurrentCompartment(type.inner, 1.5886 + "%s[%s]" % (value, index)) 1.5887 + sequenceWrapLevel -= 1 1.5888 + if not wrapElement: 1.5889 + return None 1.5890 + wrapCode = CGWrapper(CGIndenter(wrapElement), 1.5891 + pre=("for (uint32_t %s = 0; %s < %s.Length(); ++%s) {\n" % 1.5892 + (index, index, value, index)), 1.5893 + post="}\n") 1.5894 + if origType.nullable(): 1.5895 + wrapCode = CGIfWrapper(wrapCode, "!%s.IsNull()" % origValue) 1.5896 + return wrapCode 1.5897 + 1.5898 + if type.isDictionary(): 1.5899 + assert not type.nullable() 1.5900 + myDict = type.inner 1.5901 + memberWraps = [] 1.5902 + while myDict: 1.5903 + for member in myDict.members: 1.5904 + memberWrap = wrapArgIntoCurrentCompartment( 1.5905 + member, 1.5906 + "%s.%s" % (value, CGDictionary.makeMemberName(member.identifier.name))) 1.5907 + if memberWrap: 1.5908 + memberWraps.append(memberWrap) 1.5909 + myDict = myDict.parent 1.5910 + return CGList(memberWraps) if len(memberWraps) != 0 else None 1.5911 + 1.5912 + if type.isUnion(): 1.5913 + memberWraps = [] 1.5914 + if type.nullable(): 1.5915 + type = type.inner 1.5916 + value = "%s.Value()" % value 1.5917 + for member in type.flatMemberTypes: 1.5918 + memberName = getUnionMemberName(member) 1.5919 + memberWrap = wrapTypeIntoCurrentCompartment( 1.5920 + member, "%s.GetAs%s()" % (value, memberName)) 1.5921 + if memberWrap: 1.5922 + memberWrap = CGIfWrapper( 1.5923 + memberWrap, "%s.Is%s()" % (value, memberName)) 1.5924 + memberWraps.append(memberWrap) 1.5925 + return CGList(memberWraps, "else ") if len(memberWraps) != 0 else None 1.5926 + 1.5927 + if (type.isString() or type.isPrimitive() or type.isEnum() or 1.5928 + type.isGeckoInterface() or type.isCallback() or type.isDate()): 1.5929 + # All of these don't need wrapping 1.5930 + return None 1.5931 + 1.5932 + raise TypeError("Unknown type; we don't know how to wrap it in constructor " 1.5933 + "arguments: %s" % type) 1.5934 + 1.5935 + 1.5936 +def wrapArgIntoCurrentCompartment(arg, value, isMember=True): 1.5937 + """ 1.5938 + As wrapTypeIntoCurrentCompartment but handles things being optional 1.5939 + """ 1.5940 + origValue = value 1.5941 + isOptional = arg.optional and not arg.defaultValue 1.5942 + if isOptional: 1.5943 + value = value + ".Value()" 1.5944 + wrap = wrapTypeIntoCurrentCompartment(arg.type, value, isMember) 1.5945 + if wrap and isOptional: 1.5946 + wrap = CGIfWrapper(wrap, "%s.WasPassed()" % origValue) 1.5947 + return wrap 1.5948 + 1.5949 + 1.5950 +class CGPerSignatureCall(CGThing): 1.5951 + """ 1.5952 + This class handles the guts of generating code for a particular 1.5953 + call signature. A call signature consists of four things: 1.5954 + 1.5955 + 1) A return type, which can be None to indicate that there is no 1.5956 + actual return value (e.g. this is an attribute setter) or an 1.5957 + IDLType if there's an IDL type involved (including |void|). 1.5958 + 2) An argument list, which is allowed to be empty. 1.5959 + 3) A name of a native method to call. 1.5960 + 4) Whether or not this method is static. 1.5961 + 1.5962 + We also need to know whether this is a method or a getter/setter 1.5963 + to do error reporting correctly. 1.5964 + 1.5965 + The idlNode parameter can be either a method or an attr. We can query 1.5966 + |idlNode.identifier| in both cases, so we can be agnostic between the two. 1.5967 + """ 1.5968 + # XXXbz For now each entry in the argument list is either an 1.5969 + # IDLArgument or a FakeArgument, but longer-term we may want to 1.5970 + # have ways of flagging things like JSContext* or optional_argc in 1.5971 + # there. 1.5972 + 1.5973 + def __init__(self, returnType, arguments, nativeMethodName, static, 1.5974 + descriptor, idlNode, argConversionStartsAt=0, getter=False, 1.5975 + setter=False, isConstructor=False): 1.5976 + assert idlNode.isMethod() == (not getter and not setter) 1.5977 + assert idlNode.isAttr() == (getter or setter) 1.5978 + # Constructors are always static 1.5979 + assert not isConstructor or static 1.5980 + 1.5981 + CGThing.__init__(self) 1.5982 + self.returnType = returnType 1.5983 + self.descriptor = descriptor 1.5984 + self.idlNode = idlNode 1.5985 + self.extendedAttributes = descriptor.getExtendedAttributes(idlNode, 1.5986 + getter=getter, 1.5987 + setter=setter) 1.5988 + self.arguments = arguments 1.5989 + self.argCount = len(arguments) 1.5990 + cgThings = [] 1.5991 + lenientFloatCode = None 1.5992 + if idlNode.getExtendedAttribute('LenientFloat') is not None: 1.5993 + if setter: 1.5994 + lenientFloatCode = "return true;\n" 1.5995 + elif idlNode.isMethod(): 1.5996 + lenientFloatCode = ("args.rval().setUndefined();\n" 1.5997 + "return true;\n") 1.5998 + 1.5999 + argsPre = [] 1.6000 + if static: 1.6001 + nativeMethodName = "%s::%s" % (descriptor.nativeType, 1.6002 + nativeMethodName) 1.6003 + # If we're a constructor, "obj" may not be a function, so calling 1.6004 + # XrayAwareCalleeGlobal() on it is not safe. Of course in the 1.6005 + # constructor case either "obj" is an Xray or we're already in the 1.6006 + # content compartment, not the Xray compartment, so just 1.6007 + # constructing the GlobalObject from "obj" is fine. 1.6008 + if isConstructor: 1.6009 + objForGlobalObject = "obj" 1.6010 + else: 1.6011 + objForGlobalObject = "xpc::XrayAwareCalleeGlobal(obj)" 1.6012 + cgThings.append(CGGeneric(fill( 1.6013 + """ 1.6014 + GlobalObject global(cx, ${obj}); 1.6015 + if (global.Failed()) { 1.6016 + return false; 1.6017 + } 1.6018 + 1.6019 + """, 1.6020 + obj=objForGlobalObject))) 1.6021 + argsPre.append("global") 1.6022 + 1.6023 + # For JS-implemented interfaces we do not want to base the 1.6024 + # needsCx decision on the types involved, just on our extended 1.6025 + # attributes. 1.6026 + needsCx = needCx(returnType, arguments, self.extendedAttributes, 1.6027 + not descriptor.interface.isJSImplemented()) 1.6028 + if needsCx and not (static and descriptor.workers): 1.6029 + argsPre.append("cx") 1.6030 + 1.6031 + needsUnwrap = False 1.6032 + argsPost = [] 1.6033 + if isConstructor: 1.6034 + needsUnwrap = True 1.6035 + needsUnwrappedVar = False 1.6036 + unwrappedVar = "obj" 1.6037 + elif descriptor.interface.isJSImplemented(): 1.6038 + needsUnwrap = True 1.6039 + needsUnwrappedVar = True 1.6040 + argsPost.append("js::GetObjectCompartment(unwrappedObj.empty() ? obj : unwrappedObj.ref())") 1.6041 + elif needScopeObject(returnType, arguments, self.extendedAttributes, 1.6042 + descriptor.wrapperCache, True, 1.6043 + idlNode.getExtendedAttribute("StoreInSlot")): 1.6044 + needsUnwrap = True 1.6045 + needsUnwrappedVar = True 1.6046 + argsPre.append("unwrappedObj.empty() ? obj : unwrappedObj.ref()") 1.6047 + 1.6048 + if needsUnwrap and needsUnwrappedVar: 1.6049 + # We cannot assign into obj because it's a Handle, not a 1.6050 + # MutableHandle, so we need a separate Rooted. 1.6051 + cgThings.append(CGGeneric("Maybe<JS::Rooted<JSObject*> > unwrappedObj;\n")) 1.6052 + unwrappedVar = "unwrappedObj.ref()" 1.6053 + 1.6054 + if idlNode.isMethod() and idlNode.isLegacycaller(): 1.6055 + # If we can have legacycaller with identifier, we can't 1.6056 + # just use the idlNode to determine whether we're 1.6057 + # generating code for the legacycaller or not. 1.6058 + assert idlNode.isIdentifierLess() 1.6059 + # Pass in our thisVal 1.6060 + argsPre.append("args.thisv()") 1.6061 + 1.6062 + ourName = "%s.%s" % (descriptor.interface.identifier.name, 1.6063 + idlNode.identifier.name) 1.6064 + if idlNode.isMethod(): 1.6065 + argDescription = "argument %(index)d of " + ourName 1.6066 + elif setter: 1.6067 + argDescription = "value being assigned to %s" % ourName 1.6068 + else: 1.6069 + assert self.argCount == 0 1.6070 + 1.6071 + if needsUnwrap: 1.6072 + # It's very important that we construct our unwrappedObj, if we need 1.6073 + # to do it, before we might start setting up Rooted things for our 1.6074 + # arguments, so that we don't violate the stack discipline Rooted 1.6075 + # depends on. 1.6076 + cgThings.append(CGGeneric( 1.6077 + "bool objIsXray = xpc::WrapperFactory::IsXrayWrapper(obj);\n")) 1.6078 + if needsUnwrappedVar: 1.6079 + cgThings.append(CGIfWrapper( 1.6080 + CGGeneric("unwrappedObj.construct(cx, obj);\n"), 1.6081 + "objIsXray")) 1.6082 + 1.6083 + for i in range(argConversionStartsAt, self.argCount): 1.6084 + cgThings.append( 1.6085 + CGArgumentConverter(arguments[i], i, self.descriptor, 1.6086 + argDescription % {"index": i + 1}, 1.6087 + invalidEnumValueFatal=not setter, 1.6088 + lenientFloatCode=lenientFloatCode)) 1.6089 + 1.6090 + if needsUnwrap: 1.6091 + # Something depends on having the unwrapped object, so unwrap it now. 1.6092 + xraySteps = [] 1.6093 + # XXXkhuey we should be able to MOZ_ASSERT that ${obj} is 1.6094 + # not null. 1.6095 + xraySteps.append( 1.6096 + CGGeneric(string.Template(dedent(""" 1.6097 + ${obj} = js::CheckedUnwrap(${obj}); 1.6098 + if (!${obj}) { 1.6099 + return false; 1.6100 + } 1.6101 + """)).substitute({'obj': unwrappedVar}))) 1.6102 + if isConstructor: 1.6103 + # If we're called via an xray, we need to enter the underlying 1.6104 + # object's compartment and then wrap up all of our arguments into 1.6105 + # that compartment as needed. This is all happening after we've 1.6106 + # already done the conversions from JS values to WebIDL (C++) 1.6107 + # values, so we only need to worry about cases where there are 'any' 1.6108 + # or 'object' types, or other things that we represent as actual 1.6109 + # JSAPI types, present. Effectively, we're emulating a 1.6110 + # CrossCompartmentWrapper, but working with the C++ types, not the 1.6111 + # original list of JS::Values. 1.6112 + cgThings.append(CGGeneric("Maybe<JSAutoCompartment> ac;\n")) 1.6113 + xraySteps.append(CGGeneric("ac.construct(cx, obj);\n")) 1.6114 + xraySteps.extend( 1.6115 + wrapArgIntoCurrentCompartment(arg, argname, isMember=False) 1.6116 + for arg, argname in self.getArguments()) 1.6117 + 1.6118 + cgThings.append( 1.6119 + CGIfWrapper(CGList(xraySteps), 1.6120 + "objIsXray")) 1.6121 + 1.6122 + cgThings.append(CGCallGenerator( 1.6123 + self.getErrorReport() if self.isFallible() else None, 1.6124 + self.getArguments(), argsPre, returnType, 1.6125 + self.extendedAttributes, descriptor, nativeMethodName, 1.6126 + static, argsPost=argsPost)) 1.6127 + self.cgRoot = CGList(cgThings) 1.6128 + 1.6129 + def getArguments(self): 1.6130 + return [(a, "arg" + str(i)) for i, a in enumerate(self.arguments)] 1.6131 + 1.6132 + def isFallible(self): 1.6133 + return 'infallible' not in self.extendedAttributes 1.6134 + 1.6135 + def wrap_return_value(self): 1.6136 + returnsNewObject = memberReturnsNewObject(self.idlNode) 1.6137 + if returnsNewObject: 1.6138 + # We better be returning addrefed things! 1.6139 + assert(isResultAlreadyAddRefed(self.extendedAttributes) or 1.6140 + # NewObject can return raw pointers to owned objects 1.6141 + (self.returnType.isGeckoInterface() and 1.6142 + self.descriptor.getDescriptor(self.returnType.unroll().inner.identifier.name).nativeOwnership == 'owned')) 1.6143 + 1.6144 + setSlot = self.idlNode.isAttr() and self.idlNode.slotIndex is not None 1.6145 + if setSlot: 1.6146 + # For attributes in slots, we want to do some 1.6147 + # post-processing once we've wrapped them. 1.6148 + successCode = "break;\n" 1.6149 + else: 1.6150 + successCode = None 1.6151 + 1.6152 + resultTemplateValues = { 1.6153 + 'jsvalRef': 'args.rval()', 1.6154 + 'jsvalHandle': 'args.rval()', 1.6155 + 'returnsNewObject': returnsNewObject, 1.6156 + 'successCode': successCode, 1.6157 + 'obj': "reflector" if setSlot else "obj" 1.6158 + } 1.6159 + try: 1.6160 + wrapCode = wrapForType(self.returnType, self.descriptor, resultTemplateValues) 1.6161 + except MethodNotNewObjectError, err: 1.6162 + assert not returnsNewObject 1.6163 + raise TypeError("%s being returned from non-NewObject method or property %s.%s" % 1.6164 + (err.typename, 1.6165 + self.descriptor.interface.identifier.name, 1.6166 + self.idlNode.identifier.name)) 1.6167 + if setSlot: 1.6168 + # We need to make sure that our initial wrapping is done in the 1.6169 + # reflector compartment, but that we finally set args.rval() in the 1.6170 + # caller compartment. We also need to make sure that the actual 1.6171 + # wrapping steps happen inside a do/while that they can break out 1.6172 + # of. 1.6173 + 1.6174 + # postSteps are the steps that run while we're still in the 1.6175 + # reflector compartment but after we've finished the initial 1.6176 + # wrapping into args.rval(). 1.6177 + postSteps = "" 1.6178 + if self.idlNode.getExtendedAttribute("Frozen"): 1.6179 + assert self.idlNode.type.isSequence() or self.idlNode.type.isDictionary() 1.6180 + freezeValue = CGGeneric( 1.6181 + "JS::Rooted<JSObject*> rvalObj(cx, &args.rval().toObject());\n" 1.6182 + "if (!JS_FreezeObject(cx, rvalObj)) {\n" 1.6183 + " return false;\n" 1.6184 + "}\n") 1.6185 + if self.idlNode.type.nullable(): 1.6186 + freezeValue = CGIfWrapper(freezeValue, 1.6187 + "args.rval().isObject()") 1.6188 + postSteps += freezeValue.define() 1.6189 + postSteps += ("js::SetReservedSlot(reflector, %s, args.rval());\n" % 1.6190 + memberReservedSlot(self.idlNode)) 1.6191 + # For the case of Cached attributes, go ahead and preserve our 1.6192 + # wrapper if needed. We need to do this because otherwise the 1.6193 + # wrapper could get garbage-collected and the cached value would 1.6194 + # suddenly disappear, but the whole premise of cached values is that 1.6195 + # they never change without explicit action on someone's part. We 1.6196 + # don't do this for StoreInSlot, since those get dealt with during 1.6197 + # wrapper setup, and failure would involve us trying to clear an 1.6198 + # already-preserved wrapper. 1.6199 + if (self.idlNode.getExtendedAttribute("Cached") and 1.6200 + self.descriptor.wrapperCache): 1.6201 + postSteps += "PreserveWrapper(self);\n" 1.6202 + 1.6203 + wrapCode = fill( 1.6204 + """ 1.6205 + { // Make sure we wrap and store in the slot in reflector's compartment 1.6206 + JSAutoCompartment ac(cx, reflector); 1.6207 + do { // block we break out of when done wrapping 1.6208 + $*{wrapCode} 1.6209 + } while (0); 1.6210 + $*{postSteps} 1.6211 + } 1.6212 + // And now make sure args.rval() is in the caller compartment 1.6213 + return ${maybeWrap}(cx, args.rval()); 1.6214 + """, 1.6215 + wrapCode=wrapCode, 1.6216 + postSteps=postSteps, 1.6217 + maybeWrap=getMaybeWrapValueFuncForType(self.idlNode.type)) 1.6218 + return wrapCode 1.6219 + 1.6220 + def getErrorReport(self): 1.6221 + jsImplemented = "" 1.6222 + if self.descriptor.interface.isJSImplemented(): 1.6223 + jsImplemented = ", true" 1.6224 + return CGGeneric('return ThrowMethodFailedWithDetails(cx, rv, "%s", "%s"%s);\n' 1.6225 + % (self.descriptor.interface.identifier.name, 1.6226 + self.idlNode.identifier.name, 1.6227 + jsImplemented)) 1.6228 + 1.6229 + def define(self): 1.6230 + return (self.cgRoot.define() + self.wrap_return_value()) 1.6231 + 1.6232 + 1.6233 +class CGSwitch(CGList): 1.6234 + """ 1.6235 + A class to generate code for a switch statement. 1.6236 + 1.6237 + Takes three constructor arguments: an expression, a list of cases, 1.6238 + and an optional default. 1.6239 + 1.6240 + Each case is a CGCase. The default is a CGThing for the body of 1.6241 + the default case, if any. 1.6242 + """ 1.6243 + def __init__(self, expression, cases, default=None): 1.6244 + CGList.__init__(self, [CGIndenter(c) for c in cases]) 1.6245 + self.prepend(CGGeneric("switch (" + expression + ") {\n")) 1.6246 + if default is not None: 1.6247 + self.append( 1.6248 + CGIndenter( 1.6249 + CGWrapper( 1.6250 + CGIndenter(default), 1.6251 + pre="default: {\n", 1.6252 + post=" break;\n}\n"))) 1.6253 + 1.6254 + self.append(CGGeneric("}\n")) 1.6255 + 1.6256 + 1.6257 +class CGCase(CGList): 1.6258 + """ 1.6259 + A class to generate code for a case statement. 1.6260 + 1.6261 + Takes three constructor arguments: an expression, a CGThing for 1.6262 + the body (allowed to be None if there is no body), and an optional 1.6263 + argument (defaulting to False) for whether to fall through. 1.6264 + """ 1.6265 + def __init__(self, expression, body, fallThrough=False): 1.6266 + CGList.__init__(self, []) 1.6267 + self.append(CGGeneric("case " + expression + ": {\n")) 1.6268 + bodyList = CGList([body]) 1.6269 + if fallThrough: 1.6270 + bodyList.append(CGGeneric("/* Fall through */\n")) 1.6271 + else: 1.6272 + bodyList.append(CGGeneric("break;\n")) 1.6273 + self.append(CGIndenter(bodyList)) 1.6274 + self.append(CGGeneric("}\n")) 1.6275 + 1.6276 + 1.6277 +class CGMethodCall(CGThing): 1.6278 + """ 1.6279 + A class to generate selection of a method signature from a set of 1.6280 + signatures and generation of a call to that signature. 1.6281 + """ 1.6282 + def __init__(self, nativeMethodName, static, descriptor, method, 1.6283 + isConstructor=False, constructorName=None): 1.6284 + CGThing.__init__(self) 1.6285 + 1.6286 + if isConstructor: 1.6287 + assert constructorName is not None 1.6288 + methodName = constructorName 1.6289 + else: 1.6290 + methodName = "%s.%s" % (descriptor.interface.identifier.name, method.identifier.name) 1.6291 + argDesc = "argument %d of " + methodName 1.6292 + 1.6293 + def requiredArgCount(signature): 1.6294 + arguments = signature[1] 1.6295 + if len(arguments) == 0: 1.6296 + return 0 1.6297 + requiredArgs = len(arguments) 1.6298 + while requiredArgs and arguments[requiredArgs-1].optional: 1.6299 + requiredArgs -= 1 1.6300 + return requiredArgs 1.6301 + 1.6302 + def getPerSignatureCall(signature, argConversionStartsAt=0): 1.6303 + return CGPerSignatureCall(signature[0], signature[1], 1.6304 + nativeMethodName, static, descriptor, 1.6305 + method, 1.6306 + argConversionStartsAt=argConversionStartsAt, 1.6307 + isConstructor=isConstructor) 1.6308 + 1.6309 + signatures = method.signatures() 1.6310 + if len(signatures) == 1: 1.6311 + # Special case: we can just do a per-signature method call 1.6312 + # here for our one signature and not worry about switching 1.6313 + # on anything. 1.6314 + signature = signatures[0] 1.6315 + self.cgRoot = CGList([CGIndenter(getPerSignatureCall(signature))]) 1.6316 + requiredArgs = requiredArgCount(signature) 1.6317 + 1.6318 + if requiredArgs > 0: 1.6319 + code = indent(fill( # BOGUS extra blank line 1.6320 + """ 1.6321 + 1.6322 + if (args.length() < ${requiredArgs}) { 1.6323 + return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${methodName}"); 1.6324 + } 1.6325 + """, 1.6326 + requiredArgs=requiredArgs, 1.6327 + methodName=methodName)) 1.6328 + self.cgRoot.prepend(CGGeneric(code)) 1.6329 + return 1.6330 + 1.6331 + # Need to find the right overload 1.6332 + maxArgCount = method.maxArgCount 1.6333 + allowedArgCounts = method.allowedArgCounts 1.6334 + 1.6335 + argCountCases = [] 1.6336 + for argCountIdx, argCount in enumerate(allowedArgCounts): 1.6337 + possibleSignatures = method.signaturesForArgCount(argCount) 1.6338 + 1.6339 + # Try to optimize away cases when the next argCount in the list 1.6340 + # will have the same code as us; if it does, we can fall through to 1.6341 + # that case. 1.6342 + if argCountIdx+1 < len(allowedArgCounts): 1.6343 + nextPossibleSignatures = \ 1.6344 + method.signaturesForArgCount(allowedArgCounts[argCountIdx+1]) 1.6345 + else: 1.6346 + nextPossibleSignatures = None 1.6347 + if possibleSignatures == nextPossibleSignatures: 1.6348 + # Same set of signatures means we better have the same 1.6349 + # distinguishing index. So we can in fact just fall through to 1.6350 + # the next case here. 1.6351 + assert (len(possibleSignatures) == 1 or 1.6352 + (method.distinguishingIndexForArgCount(argCount) == 1.6353 + method.distinguishingIndexForArgCount(allowedArgCounts[argCountIdx+1]))) 1.6354 + argCountCases.append(CGCase(str(argCount), None, True)) 1.6355 + continue 1.6356 + 1.6357 + if len(possibleSignatures) == 1: 1.6358 + # easy case! 1.6359 + signature = possibleSignatures[0] 1.6360 + argCountCases.append( 1.6361 + CGCase(str(argCount), getPerSignatureCall(signature))) 1.6362 + continue 1.6363 + 1.6364 + distinguishingIndex = method.distinguishingIndexForArgCount(argCount) 1.6365 + 1.6366 + def distinguishingArgument(signature): 1.6367 + args = signature[1] 1.6368 + if distinguishingIndex < len(args): 1.6369 + return args[distinguishingIndex] 1.6370 + assert args[-1].variadic 1.6371 + return args[-1] 1.6372 + 1.6373 + def distinguishingType(signature): 1.6374 + return distinguishingArgument(signature).type 1.6375 + 1.6376 + for sig in possibleSignatures: 1.6377 + # We should not have "any" args at distinguishingIndex, 1.6378 + # since we have multiple possible signatures remaining, 1.6379 + # but "any" is never distinguishable from anything else. 1.6380 + assert not distinguishingType(sig).isAny() 1.6381 + # We can't handle unions at the distinguishing index. 1.6382 + if distinguishingType(sig).isUnion(): 1.6383 + raise TypeError("No support for unions as distinguishing " 1.6384 + "arguments yet: %s" % 1.6385 + distinguishingArgument(sig).location) 1.6386 + # We don't support variadics as the distinguishingArgument yet. 1.6387 + # If you want to add support, consider this case: 1.6388 + # 1.6389 + # void(long... foo); 1.6390 + # void(long bar, Int32Array baz); 1.6391 + # 1.6392 + # in which we have to convert argument 0 to long before picking 1.6393 + # an overload... but all the variadic stuff needs to go into a 1.6394 + # single array in case we pick that overload, so we have to have 1.6395 + # machinery for converting argument 0 to long and then either 1.6396 + # placing it in the variadic bit or not. Or something. We may 1.6397 + # be able to loosen this restriction if the variadic arg is in 1.6398 + # fact at distinguishingIndex, perhaps. Would need to 1.6399 + # double-check. 1.6400 + if distinguishingArgument(sig).variadic: 1.6401 + raise TypeError("No support for variadics as distinguishing " 1.6402 + "arguments yet: %s" % 1.6403 + distinguishingArgument(sig).location) 1.6404 + 1.6405 + # Convert all our arguments up to the distinguishing index. 1.6406 + # Doesn't matter which of the possible signatures we use, since 1.6407 + # they all have the same types up to that point; just use 1.6408 + # possibleSignatures[0] 1.6409 + caseBody = [CGArgumentConverter(possibleSignatures[0][1][i], 1.6410 + i, descriptor, 1.6411 + argDesc % (i + 1)) 1.6412 + for i in range(0, distinguishingIndex)] 1.6413 + 1.6414 + # Select the right overload from our set. 1.6415 + distinguishingArg = "args[%d]" % distinguishingIndex 1.6416 + 1.6417 + def tryCall(signature, indent, isDefinitelyObject=False, 1.6418 + isNullOrUndefined=False): 1.6419 + assert not isDefinitelyObject or not isNullOrUndefined 1.6420 + assert isDefinitelyObject or isNullOrUndefined 1.6421 + if isDefinitelyObject: 1.6422 + failureCode = "break;\n" 1.6423 + else: 1.6424 + failureCode = None 1.6425 + type = distinguishingType(signature) 1.6426 + # The argument at index distinguishingIndex can't possibly be 1.6427 + # unset here, because we've already checked that argc is large 1.6428 + # enough that we can examine this argument. But note that we 1.6429 + # still want to claim that optional arguments are optional, in 1.6430 + # case undefined was passed in. 1.6431 + argIsOptional = (distinguishingArgument(signature).optional and 1.6432 + not distinguishingArgument(signature).defaultValue) 1.6433 + testCode = instantiateJSToNativeConversion( 1.6434 + getJSToNativeConversionInfo(type, descriptor, 1.6435 + failureCode=failureCode, 1.6436 + isDefinitelyObject=isDefinitelyObject, 1.6437 + isNullOrUndefined=isNullOrUndefined, 1.6438 + isOptional=argIsOptional, 1.6439 + sourceDescription=(argDesc % (distinguishingIndex + 1))), 1.6440 + { 1.6441 + "declName": "arg%d" % distinguishingIndex, 1.6442 + "holderName": ("arg%d" % distinguishingIndex) + "_holder", 1.6443 + "val": distinguishingArg, 1.6444 + "mutableVal": distinguishingArg, 1.6445 + "obj": "obj", 1.6446 + "haveValue": "args.hasDefined(%d)" % distinguishingIndex 1.6447 + }, 1.6448 + checkForValue=argIsOptional) 1.6449 + caseBody.append(CGIndenter(testCode, indent)) 1.6450 + 1.6451 + # If we got this far, we know we unwrapped to the right 1.6452 + # C++ type, so just do the call. Start conversion with 1.6453 + # distinguishingIndex + 1, since we already converted 1.6454 + # distinguishingIndex. 1.6455 + caseBody.append(CGIndenter( 1.6456 + getPerSignatureCall(signature, distinguishingIndex + 1), 1.6457 + indent)) 1.6458 + 1.6459 + def hasConditionalConversion(type): 1.6460 + """ 1.6461 + Return whether the argument conversion for this type will be 1.6462 + conditional on the type of incoming JS value. For example, for 1.6463 + interface types the conversion is conditional on the incoming 1.6464 + value being isObject(). 1.6465 + 1.6466 + For the types for which this returns false, we do not have to 1.6467 + output extra isUndefined() or isNullOrUndefined() cases, because 1.6468 + null/undefined values will just fall through into our 1.6469 + unconditional conversion. 1.6470 + """ 1.6471 + if type.isString() or type.isEnum(): 1.6472 + return False 1.6473 + if type.isBoolean(): 1.6474 + distinguishingTypes = (distinguishingType(s) for s in 1.6475 + possibleSignatures) 1.6476 + return any(t.isString() or t.isEnum() or t.isNumeric() 1.6477 + for t in distinguishingTypes) 1.6478 + if type.isNumeric(): 1.6479 + distinguishingTypes = (distinguishingType(s) for s in 1.6480 + possibleSignatures) 1.6481 + return any(t.isString() or t.isEnum() 1.6482 + for t in distinguishingTypes) 1.6483 + return True 1.6484 + 1.6485 + def needsNullOrUndefinedCase(type): 1.6486 + """ 1.6487 + Return true if the type needs a special isNullOrUndefined() case 1.6488 + """ 1.6489 + return ((type.nullable() and 1.6490 + hasConditionalConversion(type)) or 1.6491 + type.isDictionary()) 1.6492 + 1.6493 + # First check for undefined and optional distinguishing arguments 1.6494 + # and output a special branch for that case. Note that we don't 1.6495 + # use distinguishingArgument here because we actualy want to 1.6496 + # exclude variadic arguments. Also note that we skip this check if 1.6497 + # we plan to output a isNullOrUndefined() special case for this 1.6498 + # argument anyway, since that will subsume our isUndefined() check. 1.6499 + # This is safe, because there can be at most one nullable 1.6500 + # distinguishing argument, so if we're it we'll definitely get 1.6501 + # picked up by the nullable handling. Also, we can skip this check 1.6502 + # if the argument has an unconditional conversion later on. 1.6503 + undefSigs = [s for s in possibleSignatures if 1.6504 + distinguishingIndex < len(s[1]) and 1.6505 + s[1][distinguishingIndex].optional and 1.6506 + hasConditionalConversion(s[1][distinguishingIndex].type) and 1.6507 + not needsNullOrUndefinedCase(s[1][distinguishingIndex].type)] 1.6508 + # Can't have multiple signatures with an optional argument at the 1.6509 + # same index. 1.6510 + assert len(undefSigs) < 2 1.6511 + if len(undefSigs) > 0: 1.6512 + caseBody.append(CGGeneric("if (%s.isUndefined()) {\n" % 1.6513 + distinguishingArg)) 1.6514 + tryCall(undefSigs[0], 2, isNullOrUndefined=True) 1.6515 + caseBody.append(CGGeneric("}\n")) 1.6516 + 1.6517 + # Next, check for null or undefined. That means looking for 1.6518 + # nullable arguments at the distinguishing index and outputting a 1.6519 + # separate branch for them. But if the nullable argument has an 1.6520 + # unconditional conversion, we don't need to do that. The reason 1.6521 + # for that is that at most one argument at the distinguishing index 1.6522 + # is nullable (since two nullable arguments are not 1.6523 + # distinguishable), and null/undefined values will always fall 1.6524 + # through to the unconditional conversion we have, if any, since 1.6525 + # they will fail whatever the conditions on the input value are for 1.6526 + # our other conversions. 1.6527 + nullOrUndefSigs = [s for s in possibleSignatures 1.6528 + if needsNullOrUndefinedCase(distinguishingType(s))] 1.6529 + # Can't have multiple nullable types here 1.6530 + assert len(nullOrUndefSigs) < 2 1.6531 + if len(nullOrUndefSigs) > 0: 1.6532 + caseBody.append(CGGeneric("if (%s.isNullOrUndefined()) {\n" % 1.6533 + distinguishingArg)) 1.6534 + tryCall(nullOrUndefSigs[0], 2, isNullOrUndefined=True) 1.6535 + caseBody.append(CGGeneric("}\n")) 1.6536 + 1.6537 + # Now check for distinguishingArg being various kinds of objects. 1.6538 + # The spec says to check for the following things in order: 1.6539 + # 1) A platform object that's not a platform array object, being 1.6540 + # passed to an interface or "object" arg. 1.6541 + # 2) A Date object being passed to a Date or "object" arg. 1.6542 + # 3) A RegExp object being passed to a RegExp or "object" arg. 1.6543 + # 4) A callable object being passed to a callback or "object" arg. 1.6544 + # 5) Any non-Date and non-RegExp object being passed to a 1.6545 + # array or sequence or callback interface dictionary or 1.6546 + # "object" arg. 1.6547 + # 1.6548 + # We can can coalesce these five cases together, as long as we make 1.6549 + # sure to check whether our object works as an interface argument 1.6550 + # before checking whether it works as an arraylike or dictionary or 1.6551 + # callback function or callback interface. 1.6552 + 1.6553 + # First grab all the overloads that have a non-callback interface 1.6554 + # (which includes typed arrays and arraybuffers) at the 1.6555 + # distinguishing index. We can also include the ones that have an 1.6556 + # "object" here, since if those are present no other object-typed 1.6557 + # argument will be. 1.6558 + objectSigs = [ 1.6559 + s for s in possibleSignatures 1.6560 + if (distinguishingType(s).isObject() or 1.6561 + distinguishingType(s).isNonCallbackInterface())] 1.6562 + 1.6563 + # And all the overloads that take Date 1.6564 + objectSigs.extend(s for s in possibleSignatures 1.6565 + if distinguishingType(s).isDate()) 1.6566 + 1.6567 + # And all the overloads that take callbacks 1.6568 + objectSigs.extend(s for s in possibleSignatures 1.6569 + if distinguishingType(s).isCallback()) 1.6570 + 1.6571 + # Now append all the overloads that take an array or sequence or 1.6572 + # dictionary or callback interface: 1.6573 + objectSigs.extend(s for s in possibleSignatures 1.6574 + if (distinguishingType(s).isArray() or 1.6575 + distinguishingType(s).isSequence() or 1.6576 + distinguishingType(s).isDictionary() or 1.6577 + distinguishingType(s).isCallbackInterface())) 1.6578 + 1.6579 + # There might be more than one thing in objectSigs; we need to check 1.6580 + # which ones we unwrap to. 1.6581 + if len(objectSigs) > 0: 1.6582 + # Here it's enough to guard on our argument being an object. The 1.6583 + # code for unwrapping non-callback interfaces, typed arrays, 1.6584 + # sequences, arrays, and Dates will just bail out and move on to 1.6585 + # the next overload if the object fails to unwrap correctly, 1.6586 + # while "object" accepts any object anyway. We could even not 1.6587 + # do the isObject() check up front here, but in cases where we 1.6588 + # have multiple object overloads it makes sense to do it only 1.6589 + # once instead of for each overload. That will also allow the 1.6590 + # unwrapping test to skip having to do codegen for the 1.6591 + # null-or-undefined case, which we already handled above. 1.6592 + caseBody.append(CGGeneric("if (%s.isObject()) {\n" % 1.6593 + distinguishingArg)) 1.6594 + for sig in objectSigs: 1.6595 + caseBody.append(CGIndenter(CGGeneric("do {\n"))) 1.6596 + # Indent by 4, since we need to indent further 1.6597 + # than our "do" statement 1.6598 + tryCall(sig, 4, isDefinitelyObject=True) 1.6599 + caseBody.append(CGIndenter(CGGeneric("} while (0);\n"))) 1.6600 + 1.6601 + caseBody.append(CGGeneric("}\n")) 1.6602 + 1.6603 + # Now we only have to consider booleans, numerics, and strings. If 1.6604 + # we only have one of them, then we can just output it. But if not, 1.6605 + # then we need to output some of the cases conditionally: if we have 1.6606 + # a string overload, then boolean and numeric are conditional, and 1.6607 + # if not then boolean is conditional if we have a numeric overload. 1.6608 + def findUniqueSignature(filterLambda): 1.6609 + sigs = filter(filterLambda, possibleSignatures) 1.6610 + assert len(sigs) < 2 1.6611 + if len(sigs) > 0: 1.6612 + return sigs[0] 1.6613 + return None 1.6614 + 1.6615 + stringSignature = findUniqueSignature( 1.6616 + lambda s: (distinguishingType(s).isString() or 1.6617 + distinguishingType(s).isEnum())) 1.6618 + numericSignature = findUniqueSignature( 1.6619 + lambda s: distinguishingType(s).isNumeric()) 1.6620 + booleanSignature = findUniqueSignature( 1.6621 + lambda s: distinguishingType(s).isBoolean()) 1.6622 + 1.6623 + if stringSignature or numericSignature: 1.6624 + booleanCondition = "%s.isBoolean()" 1.6625 + else: 1.6626 + booleanCondition = None 1.6627 + 1.6628 + if stringSignature: 1.6629 + numericCondition = "%s.isNumber()" 1.6630 + else: 1.6631 + numericCondition = None 1.6632 + 1.6633 + def addCase(sig, condition): 1.6634 + sigCode = getPerSignatureCall(sig, distinguishingIndex) 1.6635 + if condition: 1.6636 + sigCode = CGIfWrapper(sigCode, 1.6637 + condition % distinguishingArg) 1.6638 + caseBody.append(sigCode) 1.6639 + 1.6640 + if booleanSignature: 1.6641 + addCase(booleanSignature, booleanCondition) 1.6642 + if numericSignature: 1.6643 + addCase(numericSignature, numericCondition) 1.6644 + if stringSignature: 1.6645 + addCase(stringSignature, None) 1.6646 + 1.6647 + if (not booleanSignature and not numericSignature and 1.6648 + not stringSignature): 1.6649 + # Just throw; we have no idea what we're supposed to 1.6650 + # do with this. 1.6651 + caseBody.append(CGGeneric( 1.6652 + 'return ThrowErrorMessage(cx, MSG_OVERLOAD_RESOLUTION_FAILED, "%d", "%d", "%s");\n' % 1.6653 + (distinguishingIndex + 1, argCount, methodName))) 1.6654 + 1.6655 + argCountCases.append(CGCase(str(argCount), CGList(caseBody))) 1.6656 + 1.6657 + overloadCGThings = [] 1.6658 + overloadCGThings.append( 1.6659 + CGGeneric("unsigned argcount = std::min(args.length(), %du);\n" % 1.6660 + maxArgCount)) 1.6661 + overloadCGThings.append( 1.6662 + CGSwitch("argcount", 1.6663 + argCountCases, 1.6664 + # BOGUS extra blank line at end of default block 1.6665 + CGGeneric('return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "%s");\n\n' % 1.6666 + methodName))) 1.6667 + overloadCGThings.append( 1.6668 + CGGeneric('MOZ_CRASH("We have an always-returning default case");\n' 1.6669 + 'return false;\n')) 1.6670 + self.cgRoot = CGWrapper(CGIndenter(CGList(overloadCGThings)), 1.6671 + pre="\n") 1.6672 + 1.6673 + def define(self): 1.6674 + return self.cgRoot.define() 1.6675 + 1.6676 + 1.6677 +class CGGetterCall(CGPerSignatureCall): 1.6678 + """ 1.6679 + A class to generate a native object getter call for a particular IDL 1.6680 + getter. 1.6681 + """ 1.6682 + def __init__(self, returnType, nativeMethodName, descriptor, attr): 1.6683 + CGPerSignatureCall.__init__(self, returnType, [], nativeMethodName, 1.6684 + attr.isStatic(), descriptor, attr, 1.6685 + getter=True) 1.6686 + 1.6687 + 1.6688 +class FakeArgument(): 1.6689 + """ 1.6690 + A class that quacks like an IDLArgument. This is used to make 1.6691 + setters look like method calls or for special operations. 1.6692 + """ 1.6693 + def __init__(self, type, interfaceMember, name="arg", allowTreatNonCallableAsNull=False): 1.6694 + self.type = type 1.6695 + self.optional = False 1.6696 + self.variadic = False 1.6697 + self.defaultValue = None 1.6698 + self._allowTreatNonCallableAsNull = allowTreatNonCallableAsNull 1.6699 + self.treatNullAs = interfaceMember.treatNullAs 1.6700 + if isinstance(interfaceMember, IDLAttribute): 1.6701 + self.enforceRange = interfaceMember.enforceRange 1.6702 + self.clamp = interfaceMember.clamp 1.6703 + else: 1.6704 + self.enforceRange = False 1.6705 + self.clamp = False 1.6706 + 1.6707 + class FakeIdentifier(): 1.6708 + def __init__(self): 1.6709 + self.name = name 1.6710 + self.identifier = FakeIdentifier() 1.6711 + 1.6712 + def allowTreatNonCallableAsNull(self): 1.6713 + return self._allowTreatNonCallableAsNull 1.6714 + 1.6715 + 1.6716 +class CGSetterCall(CGPerSignatureCall): 1.6717 + """ 1.6718 + A class to generate a native object setter call for a particular IDL 1.6719 + setter. 1.6720 + """ 1.6721 + def __init__(self, argType, nativeMethodName, descriptor, attr): 1.6722 + CGPerSignatureCall.__init__(self, None, [FakeArgument(argType, attr, allowTreatNonCallableAsNull=True)], 1.6723 + nativeMethodName, attr.isStatic(), 1.6724 + descriptor, attr, setter=True) 1.6725 + 1.6726 + def wrap_return_value(self): 1.6727 + attr = self.idlNode 1.6728 + if self.descriptor.wrapperCache and attr.slotIndex is not None: 1.6729 + if attr.getExtendedAttribute("StoreInSlot"): 1.6730 + args = "cx, self" 1.6731 + else: 1.6732 + args = "self" 1.6733 + clearSlot = ("ClearCached%sValue(%s);\n" % 1.6734 + (MakeNativeName(self.idlNode.identifier.name), args)) 1.6735 + else: 1.6736 + clearSlot = "" 1.6737 + 1.6738 + # We have no return value 1.6739 + return ("\n" 1.6740 + "%s" 1.6741 + "return true;\n" % clearSlot) 1.6742 + 1.6743 + 1.6744 +class CGAbstractBindingMethod(CGAbstractStaticMethod): 1.6745 + """ 1.6746 + Common class to generate the JSNatives for all our methods, getters, and 1.6747 + setters. This will generate the function declaration and unwrap the 1.6748 + |this| object. Subclasses are expected to override the generate_code 1.6749 + function to do the rest of the work. This function should return a 1.6750 + CGThing which is already properly indented. 1.6751 + 1.6752 + getThisObj should be code for getting a JSObject* for the binding 1.6753 + object. If this is None, we will auto-generate code based on 1.6754 + descriptor to do the right thing. "" can be passed in if the 1.6755 + binding object is already stored in 'obj'. 1.6756 + 1.6757 + callArgs should be code for getting a JS::CallArgs into a variable 1.6758 + called 'args'. This can be "" if there is already such a variable 1.6759 + around. 1.6760 + 1.6761 + If allowCrossOriginThis is true, then this-unwrapping will first do an 1.6762 + UncheckedUnwrap and after that operate on the result. 1.6763 + """ 1.6764 + def __init__(self, descriptor, name, args, unwrapFailureCode=None, 1.6765 + getThisObj=None, 1.6766 + callArgs="JS::CallArgs args = JS::CallArgsFromVp(argc, vp);\n", 1.6767 + allowCrossOriginThis=False): 1.6768 + CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args) 1.6769 + 1.6770 + if unwrapFailureCode is None: 1.6771 + self.unwrapFailureCode = 'return ThrowErrorMessage(cx, MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, "Value", "%s");\n' % descriptor.interface.identifier.name 1.6772 + else: 1.6773 + self.unwrapFailureCode = unwrapFailureCode 1.6774 + 1.6775 + if getThisObj == "": 1.6776 + self.getThisObj = None 1.6777 + else: 1.6778 + if getThisObj is None: 1.6779 + if descriptor.interface.isOnGlobalProtoChain(): 1.6780 + ensureCondition = "!args.thisv().isNullOrUndefined() && !args.thisv().isObject()" 1.6781 + getThisObj = "args.thisv().isObject() ? &args.thisv().toObject() : js::GetGlobalForObjectCrossCompartment(&args.callee())" 1.6782 + else: 1.6783 + ensureCondition = "!args.thisv().isObject()" 1.6784 + getThisObj = "&args.thisv().toObject()" 1.6785 + unwrapFailureCode = self.unwrapFailureCode % {'securityError': 'false'} 1.6786 + ensureThisObj = CGIfWrapper(CGGeneric(unwrapFailureCode), 1.6787 + ensureCondition) 1.6788 + else: 1.6789 + ensureThisObj = None 1.6790 + self.getThisObj = CGList( 1.6791 + [ensureThisObj, 1.6792 + CGGeneric("JS::Rooted<JSObject*> obj(cx, %s);\n" % 1.6793 + getThisObj)]) 1.6794 + self.callArgs = callArgs 1.6795 + self.allowCrossOriginThis = allowCrossOriginThis 1.6796 + 1.6797 + def definition_body(self): 1.6798 + body = self.callArgs 1.6799 + if self.getThisObj is not None: 1.6800 + body += self.getThisObj.define() + "\n" 1.6801 + body += "%s* self;\n" % self.descriptor.nativeType 1.6802 + 1.6803 + # Our descriptor might claim that we're not castable, simply because 1.6804 + # we're someone's consequential interface. But for this-unwrapping, we 1.6805 + # know that we're the real deal. So fake a descriptor here for 1.6806 + # consumption by CastableObjectUnwrapper. 1.6807 + body += str(CastableObjectUnwrapper( 1.6808 + self.descriptor, 1.6809 + "obj", "self", self.unwrapFailureCode, 1.6810 + allowCrossOriginObj=self.allowCrossOriginThis)) 1.6811 + 1.6812 + return indent(body) + self.generate_code().define() 1.6813 + 1.6814 + def generate_code(self): 1.6815 + assert False # Override me 1.6816 + 1.6817 + 1.6818 +class CGAbstractStaticBindingMethod(CGAbstractStaticMethod): 1.6819 + """ 1.6820 + Common class to generate the JSNatives for all our static methods, getters 1.6821 + and setters. This will generate the function declaration and unwrap the 1.6822 + global object. Subclasses are expected to override the generate_code 1.6823 + function to do the rest of the work. This function should return a 1.6824 + CGThing which is already properly indented. 1.6825 + """ 1.6826 + def __init__(self, descriptor, name): 1.6827 + args = [Argument('JSContext*', 'cx'), 1.6828 + Argument('unsigned', 'argc'), 1.6829 + Argument('JS::Value*', 'vp')] 1.6830 + CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args) 1.6831 + 1.6832 + def definition_body(self): 1.6833 + # Make sure that "obj" is in the same compartment as "cx", since we'll 1.6834 + # later use it to wrap return values. 1.6835 + unwrap = indent(dedent(""" 1.6836 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.6837 + JS::Rooted<JSObject*> obj(cx, &args.callee()); 1.6838 + 1.6839 + """)) 1.6840 + return unwrap + self.generate_code().define() 1.6841 + 1.6842 + def generate_code(self): 1.6843 + assert False # Override me 1.6844 + 1.6845 + 1.6846 +def MakeNativeName(name): 1.6847 + return name[0].upper() + name[1:] 1.6848 + 1.6849 + 1.6850 +class CGGenericMethod(CGAbstractBindingMethod): 1.6851 + """ 1.6852 + A class for generating the C++ code for an IDL method. 1.6853 + 1.6854 + If allowCrossOriginThis is true, then this-unwrapping will first do an 1.6855 + UncheckedUnwrap and after that operate on the result. 1.6856 + """ 1.6857 + def __init__(self, descriptor, allowCrossOriginThis=False): 1.6858 + args = [Argument('JSContext*', 'cx'), 1.6859 + Argument('unsigned', 'argc'), 1.6860 + Argument('JS::Value*', 'vp')] 1.6861 + unwrapFailureCode = ( 1.6862 + 'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForMethod(%%(securityError)s), "%s");\n' % 1.6863 + descriptor.interface.identifier.name) 1.6864 + name = "genericCrossOriginMethod" if allowCrossOriginThis else "genericMethod" 1.6865 + CGAbstractBindingMethod.__init__(self, descriptor, name, 1.6866 + args, 1.6867 + unwrapFailureCode=unwrapFailureCode, 1.6868 + allowCrossOriginThis=allowCrossOriginThis) 1.6869 + 1.6870 + def generate_code(self): 1.6871 + return CGGeneric(indent(dedent(""" 1.6872 + const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); 1.6873 + MOZ_ASSERT(info->type() == JSJitInfo::Method); 1.6874 + JSJitMethodOp method = info->method; 1.6875 + return method(cx, obj, self, JSJitMethodCallArgs(args)); 1.6876 + """))) 1.6877 + 1.6878 + 1.6879 +class CGSpecializedMethod(CGAbstractStaticMethod): 1.6880 + """ 1.6881 + A class for generating the C++ code for a specialized method that the JIT 1.6882 + can call with lower overhead. 1.6883 + """ 1.6884 + def __init__(self, descriptor, method): 1.6885 + self.method = method 1.6886 + name = CppKeywords.checkMethodName(method.identifier.name) 1.6887 + args = [Argument('JSContext*', 'cx'), 1.6888 + Argument('JS::Handle<JSObject*>', 'obj'), 1.6889 + Argument('%s*' % descriptor.nativeType, 'self'), 1.6890 + Argument('const JSJitMethodCallArgs&', 'args')] 1.6891 + CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args) 1.6892 + 1.6893 + def definition_body(self): 1.6894 + nativeName = CGSpecializedMethod.makeNativeName(self.descriptor, 1.6895 + self.method) 1.6896 + return CGMethodCall(nativeName, self.method.isStatic(), self.descriptor, 1.6897 + self.method).define() 1.6898 + 1.6899 + @staticmethod 1.6900 + def makeNativeName(descriptor, method): 1.6901 + name = method.identifier.name 1.6902 + return MakeNativeName(descriptor.binaryNames.get(name, name)) 1.6903 + 1.6904 + 1.6905 +class CGMethodPromiseWrapper(CGAbstractStaticMethod): 1.6906 + """ 1.6907 + A class for generating a wrapper around another method that will 1.6908 + convert exceptions to promises. 1.6909 + """ 1.6910 + def __init__(self, descriptor, methodToWrap): 1.6911 + self.method = methodToWrap 1.6912 + name = self.makeName(methodToWrap.name) 1.6913 + args = list(methodToWrap.args) 1.6914 + CGAbstractStaticMethod.__init__(self, descriptor, name, 'bool', args) 1.6915 + 1.6916 + def definition_body(self): 1.6917 + return indent(fill( 1.6918 + """ 1.6919 + // Make sure to save the callee before someone maybe messes 1.6920 + // with rval(). 1.6921 + JS::Rooted<JSObject*> callee(cx, &args.callee()); 1.6922 + bool ok = ${methodName}(${args}); 1.6923 + if (ok) { 1.6924 + return true; 1.6925 + } 1.6926 + return ConvertExceptionToPromise(cx, xpc::XrayAwareCalleeGlobal(callee), 1.6927 + args.rval()); 1.6928 + """, 1.6929 + methodName=self.method.name, 1.6930 + args=", ".join(arg.name for arg in self.args))) 1.6931 + 1.6932 + @staticmethod 1.6933 + def makeName(methodName): 1.6934 + return methodName + "_promiseWrapper" 1.6935 + 1.6936 + 1.6937 +class CGJsonifierMethod(CGSpecializedMethod): 1.6938 + def __init__(self, descriptor, method): 1.6939 + assert method.isJsonifier() 1.6940 + CGSpecializedMethod.__init__(self, descriptor, method) 1.6941 + 1.6942 + def definition_body(self): 1.6943 + ret = dedent(""" 1.6944 + JS::Rooted<JSObject*> result(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); 1.6945 + if (!result) { 1.6946 + return false; 1.6947 + } 1.6948 + """) 1.6949 + for m in self.descriptor.interface.members: 1.6950 + if m.isAttr() and not m.isStatic() and m.type.isSerializable(): 1.6951 + ret += fill( 1.6952 + """ 1.6953 + { // scope for "temp" 1.6954 + JS::Rooted<JS::Value> temp(cx); 1.6955 + if (!get_${name}(cx, obj, self, JSJitGetterCallArgs(&temp))) { 1.6956 + return false; 1.6957 + } 1.6958 + if (!JS_DefineProperty(cx, result, "${name}", temp, JSPROP_ENUMERATE)) { 1.6959 + return false; 1.6960 + } 1.6961 + } 1.6962 + """, 1.6963 + name=m.identifier.name) 1.6964 + 1.6965 + ret += ('args.rval().setObject(*result);\n' 1.6966 + 'return true;\n') 1.6967 + return indent(ret) 1.6968 + 1.6969 + 1.6970 +class CGLegacyCallHook(CGAbstractBindingMethod): 1.6971 + """ 1.6972 + Call hook for our object 1.6973 + """ 1.6974 + def __init__(self, descriptor): 1.6975 + self._legacycaller = descriptor.operations["LegacyCaller"] 1.6976 + args = [Argument('JSContext*', 'cx'), 1.6977 + Argument('unsigned', 'argc'), 1.6978 + Argument('JS::Value*', 'vp')] 1.6979 + # Our "self" is actually the callee in this case, not the thisval. 1.6980 + CGAbstractBindingMethod.__init__( 1.6981 + self, descriptor, LEGACYCALLER_HOOK_NAME, 1.6982 + args, getThisObj="&args.callee()") 1.6983 + 1.6984 + def define(self): 1.6985 + if not self._legacycaller: 1.6986 + return "" 1.6987 + return CGAbstractBindingMethod.define(self) 1.6988 + 1.6989 + def generate_code(self): 1.6990 + name = self._legacycaller.identifier.name 1.6991 + nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name)) 1.6992 + return CGMethodCall(nativeName, False, self.descriptor, 1.6993 + self._legacycaller) 1.6994 + 1.6995 + 1.6996 +class CGNewResolveHook(CGAbstractBindingMethod): 1.6997 + """ 1.6998 + NewResolve hook for objects with custom hooks. 1.6999 + """ 1.7000 + def __init__(self, descriptor): 1.7001 + assert descriptor.interface.getExtendedAttribute("NeedNewResolve") 1.7002 + 1.7003 + args = [Argument('JSContext*', 'cx'), 1.7004 + Argument('JS::Handle<JSObject*>', 'obj'), 1.7005 + Argument('JS::Handle<jsid>', 'id'), 1.7006 + Argument('JS::MutableHandle<JSObject*>', 'objp')] 1.7007 + # Our "self" is actually the "obj" argument in this case, not the thisval. 1.7008 + CGAbstractBindingMethod.__init__( 1.7009 + self, descriptor, NEWRESOLVE_HOOK_NAME, 1.7010 + args, getThisObj="", callArgs="") 1.7011 + 1.7012 + def generate_code(self): 1.7013 + return CGGeneric(indent(dedent(""" 1.7014 + JS::Rooted<JSPropertyDescriptor> desc(cx); 1.7015 + if (!self->DoNewResolve(cx, obj, id, &desc)) { 1.7016 + return false; 1.7017 + } 1.7018 + if (!desc.object()) { 1.7019 + return true; 1.7020 + } 1.7021 + // If desc.value() is undefined, then the DoNewResolve call 1.7022 + // has already defined it on the object. Don't try to also 1.7023 + // define it. 1.7024 + if (!desc.value().isUndefined() && 1.7025 + !JS_DefinePropertyById(cx, obj, id, desc.value(), 1.7026 + desc.getter(), desc.setter(), 1.7027 + desc.attributes())) { 1.7028 + return false; 1.7029 + } 1.7030 + objp.set(obj); 1.7031 + return true; 1.7032 + """))) 1.7033 + 1.7034 + def definition_body(self): 1.7035 + if self.descriptor.interface.getExtendedAttribute("Global"): 1.7036 + # Resolve standard classes 1.7037 + prefix = indent(dedent(""" 1.7038 + if (!ResolveGlobal(cx, obj, id, objp)) { 1.7039 + return false; 1.7040 + } 1.7041 + if (objp) { 1.7042 + return true; 1.7043 + } 1.7044 + 1.7045 + """)) 1.7046 + else: 1.7047 + prefix = "" 1.7048 + return prefix + CGAbstractBindingMethod.definition_body(self) 1.7049 + 1.7050 + 1.7051 +class CGEnumerateHook(CGAbstractBindingMethod): 1.7052 + """ 1.7053 + Enumerate hook for objects with custom hooks. 1.7054 + """ 1.7055 + def __init__(self, descriptor): 1.7056 + assert descriptor.interface.getExtendedAttribute("NeedNewResolve") 1.7057 + 1.7058 + args = [Argument('JSContext*', 'cx'), 1.7059 + Argument('JS::Handle<JSObject*>', 'obj')] 1.7060 + # Our "self" is actually the "obj" argument in this case, not the thisval. 1.7061 + CGAbstractBindingMethod.__init__( 1.7062 + self, descriptor, ENUMERATE_HOOK_NAME, 1.7063 + args, getThisObj="", callArgs="") 1.7064 + 1.7065 + def generate_code(self): 1.7066 + return CGGeneric(indent(dedent(""" 1.7067 + nsAutoTArray<nsString, 8> names; 1.7068 + ErrorResult rv; 1.7069 + self->GetOwnPropertyNames(cx, names, rv); 1.7070 + rv.WouldReportJSException(); 1.7071 + if (rv.Failed()) { 1.7072 + return ThrowMethodFailedWithDetails(cx, rv, "%s", "enumerate"); 1.7073 + } 1.7074 + JS::Rooted<JS::Value> dummy(cx); 1.7075 + for (uint32_t i = 0; i < names.Length(); ++i) { 1.7076 + if (!JS_LookupUCProperty(cx, obj, names[i].get(), names[i].Length(), &dummy)) { 1.7077 + return false; 1.7078 + } 1.7079 + } 1.7080 + return true; 1.7081 + """))) 1.7082 + 1.7083 + def definition_body(self): 1.7084 + if self.descriptor.interface.getExtendedAttribute("Global"): 1.7085 + # Enumerate standard classes 1.7086 + prefix = indent(dedent(""" 1.7087 + if (!EnumerateGlobal(cx, obj)) { 1.7088 + return false; 1.7089 + } 1.7090 + 1.7091 + """)) 1.7092 + else: 1.7093 + prefix = "" 1.7094 + return prefix + CGAbstractBindingMethod.definition_body(self) 1.7095 + 1.7096 + 1.7097 +class CppKeywords(): 1.7098 + """ 1.7099 + A class for checking if method names declared in webidl 1.7100 + are not in conflict with C++ keywords. 1.7101 + """ 1.7102 + keywords = frozenset([ 1.7103 + 'alignas', 'alignof', 'and', 'and_eq', 'asm', 'assert', 'auto', 'bitand', 'bitor', 'bool', 1.7104 + 'break', 'case', 'catch', 'char', 'char16_t', 'char32_t', 'class', 'compl', 'const', 1.7105 + 'constexpr', 'const_cast', 'continue', 'decltype', 'default', 'delete', 'do', 'double', 1.7106 + 'dynamic_cast', 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'final', 'float', 1.7107 + 'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new', 1.7108 + 'noexcept', 'not', 'not_eq', 'nullptr', 'operator', 'or', 'or_eq', 'override', 'private', 1.7109 + 'protected', 'public', 'register', 'reinterpret_cast', 'return', 'short', 'signed', 1.7110 + 'sizeof', 'static', 'static_assert', 'static_cast', 'struct', 'switch', 'template', 'this', 1.7111 + 'thread_local', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union', 1.7112 + 'unsigned', 'using', 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'xor', 'xor_eq']) 1.7113 + 1.7114 + @staticmethod 1.7115 + def checkMethodName(name): 1.7116 + # Double '_' because 'assert' and '_assert' cannot be used in MS2013 compiler. 1.7117 + # Bug 964892 and bug 963560. 1.7118 + if name in CppKeywords.keywords: 1.7119 + name = '_' + name + '_' 1.7120 + return name 1.7121 + 1.7122 + 1.7123 +class CGStaticMethod(CGAbstractStaticBindingMethod): 1.7124 + """ 1.7125 + A class for generating the C++ code for an IDL static method. 1.7126 + """ 1.7127 + def __init__(self, descriptor, method): 1.7128 + self.method = method 1.7129 + name = method.identifier.name 1.7130 + CGAbstractStaticBindingMethod.__init__(self, descriptor, name) 1.7131 + 1.7132 + def generate_code(self): 1.7133 + nativeName = CGSpecializedMethod.makeNativeName(self.descriptor, 1.7134 + self.method) 1.7135 + return CGMethodCall(nativeName, True, self.descriptor, self.method) 1.7136 + 1.7137 + 1.7138 +class CGGenericGetter(CGAbstractBindingMethod): 1.7139 + """ 1.7140 + A class for generating the C++ code for an IDL attribute getter. 1.7141 + """ 1.7142 + def __init__(self, descriptor, lenientThis=False, allowCrossOriginThis=False): 1.7143 + args = [Argument('JSContext*', 'cx'), 1.7144 + Argument('unsigned', 'argc'), 1.7145 + Argument('JS::Value*', 'vp')] 1.7146 + if lenientThis: 1.7147 + name = "genericLenientGetter" 1.7148 + unwrapFailureCode = dedent(""" 1.7149 + MOZ_ASSERT(!JS_IsExceptionPending(cx)); 1.7150 + if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) { 1.7151 + return false; 1.7152 + } 1.7153 + args.rval().set(JS::UndefinedValue()); 1.7154 + return true; 1.7155 + """) 1.7156 + else: 1.7157 + if allowCrossOriginThis: 1.7158 + name = "genericCrossOriginGetter" 1.7159 + else: 1.7160 + name = "genericGetter" 1.7161 + unwrapFailureCode = ( 1.7162 + 'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForGetter(%%(securityError)s), "%s");\n' % 1.7163 + descriptor.interface.identifier.name) 1.7164 + CGAbstractBindingMethod.__init__(self, descriptor, name, args, 1.7165 + unwrapFailureCode, 1.7166 + allowCrossOriginThis=allowCrossOriginThis) 1.7167 + 1.7168 + def generate_code(self): 1.7169 + return CGGeneric(indent(dedent(""" 1.7170 + const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); 1.7171 + MOZ_ASSERT(info->type() == JSJitInfo::Getter); 1.7172 + JSJitGetterOp getter = info->getter; 1.7173 + return getter(cx, obj, self, JSJitGetterCallArgs(args)); 1.7174 + """))) 1.7175 + 1.7176 + 1.7177 +class CGSpecializedGetter(CGAbstractStaticMethod): 1.7178 + """ 1.7179 + A class for generating the code for a specialized attribute getter 1.7180 + that the JIT can call with lower overhead. 1.7181 + """ 1.7182 + def __init__(self, descriptor, attr): 1.7183 + self.attr = attr 1.7184 + name = 'get_' + attr.identifier.name 1.7185 + args = [ 1.7186 + Argument('JSContext*', 'cx'), 1.7187 + Argument('JS::Handle<JSObject*>', 'obj'), 1.7188 + Argument('%s*' % descriptor.nativeType, 'self'), 1.7189 + Argument('JSJitGetterCallArgs', 'args') 1.7190 + ] 1.7191 + CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args) 1.7192 + 1.7193 + def definition_body(self): 1.7194 + nativeName = CGSpecializedGetter.makeNativeName(self.descriptor, 1.7195 + self.attr) 1.7196 + if self.attr.slotIndex is not None: 1.7197 + if (self.descriptor.hasXPConnectImpls and 1.7198 + (self.descriptor.interface.identifier.name != 'Window' or 1.7199 + self.attr.identifier.name != 'document')): 1.7200 + raise TypeError("Interface '%s' has XPConnect impls, so we " 1.7201 + "can't use our slot for property '%s'!" % 1.7202 + (self.descriptor.interface.identifier.name, 1.7203 + self.attr.identifier.name)) 1.7204 + prefix = indent(fill( 1.7205 + """ 1.7206 + // Have to either root across the getter call or reget after. 1.7207 + JS::Rooted<JSObject*> reflector(cx); 1.7208 + // Safe to do an unchecked unwrap, since we've gotten this far. 1.7209 + // Also make sure to unwrap outer windows, since we want the 1.7210 + // real DOM object. 1.7211 + reflector = IsDOMObject(obj) ? obj : js::UncheckedUnwrap(obj, /* stopAtOuter = */ false); 1.7212 + { 1.7213 + // Scope for cachedVal 1.7214 + JS::Value cachedVal = js::GetReservedSlot(reflector, ${slot}); 1.7215 + if (!cachedVal.isUndefined()) { 1.7216 + args.rval().set(cachedVal); 1.7217 + // The cached value is in the compartment of reflector, 1.7218 + // so wrap into the caller compartment as needed. 1.7219 + return ${maybeWrap}(cx, args.rval()); 1.7220 + } 1.7221 + } 1.7222 + 1.7223 + """, 1.7224 + slot=memberReservedSlot(self.attr), 1.7225 + maybeWrap=getMaybeWrapValueFuncForType(self.attr.type))) 1.7226 + else: 1.7227 + prefix = "" 1.7228 + 1.7229 + return (prefix + 1.7230 + indent(CGGetterCall(self.attr.type, nativeName, 1.7231 + self.descriptor, self.attr).define())) 1.7232 + 1.7233 + @staticmethod 1.7234 + def makeNativeName(descriptor, attr): 1.7235 + name = attr.identifier.name 1.7236 + nativeName = MakeNativeName(descriptor.binaryNames.get(name, name)) 1.7237 + # resultOutParam does not depend on whether resultAlreadyAddRefed is set 1.7238 + _, resultOutParam, _, _ = getRetvalDeclarationForType(attr.type, 1.7239 + descriptor, 1.7240 + False) 1.7241 + infallible = ('infallible' in 1.7242 + descriptor.getExtendedAttributes(attr, getter=True)) 1.7243 + if resultOutParam or attr.type.nullable() or not infallible: 1.7244 + nativeName = "Get" + nativeName 1.7245 + return nativeName 1.7246 + 1.7247 + 1.7248 +class CGStaticGetter(CGAbstractStaticBindingMethod): 1.7249 + """ 1.7250 + A class for generating the C++ code for an IDL static attribute getter. 1.7251 + """ 1.7252 + def __init__(self, descriptor, attr): 1.7253 + self.attr = attr 1.7254 + name = 'get_' + attr.identifier.name 1.7255 + CGAbstractStaticBindingMethod.__init__(self, descriptor, name) 1.7256 + 1.7257 + def generate_code(self): 1.7258 + nativeName = CGSpecializedGetter.makeNativeName(self.descriptor, 1.7259 + self.attr) 1.7260 + return CGIndenter(CGGetterCall(self.attr.type, nativeName, 1.7261 + self.descriptor, self.attr)) 1.7262 + 1.7263 + 1.7264 +class CGGenericSetter(CGAbstractBindingMethod): 1.7265 + """ 1.7266 + A class for generating the C++ code for an IDL attribute setter. 1.7267 + """ 1.7268 + def __init__(self, descriptor, lenientThis=False, allowCrossOriginThis=False): 1.7269 + args = [Argument('JSContext*', 'cx'), 1.7270 + Argument('unsigned', 'argc'), 1.7271 + Argument('JS::Value*', 'vp')] 1.7272 + if lenientThis: 1.7273 + name = "genericLenientSetter" 1.7274 + unwrapFailureCode = dedent(""" 1.7275 + MOZ_ASSERT(!JS_IsExceptionPending(cx)); 1.7276 + if (!ReportLenientThisUnwrappingFailure(cx, &args.callee())) { 1.7277 + return false; 1.7278 + } 1.7279 + args.rval().set(JS::UndefinedValue()); 1.7280 + return true; 1.7281 + """) 1.7282 + else: 1.7283 + if allowCrossOriginThis: 1.7284 + name = "genericCrossOriginSetter" 1.7285 + else: 1.7286 + name = "genericSetter" 1.7287 + unwrapFailureCode = ( 1.7288 + 'return ThrowInvalidThis(cx, args, GetInvalidThisErrorForSetter(%%(securityError)s), "%s");\n' % 1.7289 + descriptor.interface.identifier.name) 1.7290 + 1.7291 + CGAbstractBindingMethod.__init__(self, descriptor, name, args, 1.7292 + unwrapFailureCode, 1.7293 + allowCrossOriginThis=allowCrossOriginThis) 1.7294 + 1.7295 + def generate_code(self): 1.7296 + return CGGeneric(indent(fill( 1.7297 + """ 1.7298 + if (args.length() == 0) { 1.7299 + return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${name} attribute setter"); 1.7300 + } 1.7301 + const JSJitInfo *info = FUNCTION_VALUE_TO_JITINFO(args.calleev()); 1.7302 + MOZ_ASSERT(info->type() == JSJitInfo::Setter); 1.7303 + JSJitSetterOp setter = info->setter; 1.7304 + if (!setter(cx, obj, self, JSJitSetterCallArgs(args))) { 1.7305 + return false; 1.7306 + } 1.7307 + args.rval().set(JSVAL_VOID); 1.7308 + return true; 1.7309 + """, 1.7310 + name=self.descriptor.interface.identifier.name))) 1.7311 + 1.7312 + 1.7313 +class CGSpecializedSetter(CGAbstractStaticMethod): 1.7314 + """ 1.7315 + A class for generating the code for a specialized attribute setter 1.7316 + that the JIT can call with lower overhead. 1.7317 + """ 1.7318 + def __init__(self, descriptor, attr): 1.7319 + self.attr = attr 1.7320 + name = 'set_' + attr.identifier.name 1.7321 + args = [Argument('JSContext*', 'cx'), 1.7322 + Argument('JS::Handle<JSObject*>', 'obj'), 1.7323 + Argument('%s*' % descriptor.nativeType, 'self'), 1.7324 + Argument('JSJitSetterCallArgs', 'args')] 1.7325 + CGAbstractStaticMethod.__init__(self, descriptor, name, "bool", args) 1.7326 + 1.7327 + def definition_body(self): 1.7328 + nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, 1.7329 + self.attr) 1.7330 + return CGIndenter(CGSetterCall(self.attr.type, nativeName, 1.7331 + self.descriptor, self.attr)).define() 1.7332 + 1.7333 + @staticmethod 1.7334 + def makeNativeName(descriptor, attr): 1.7335 + name = attr.identifier.name 1.7336 + return "Set" + MakeNativeName(descriptor.binaryNames.get(name, name)) 1.7337 + 1.7338 + 1.7339 +class CGStaticSetter(CGAbstractStaticBindingMethod): 1.7340 + """ 1.7341 + A class for generating the C++ code for an IDL static attribute setter. 1.7342 + """ 1.7343 + def __init__(self, descriptor, attr): 1.7344 + self.attr = attr 1.7345 + name = 'set_' + attr.identifier.name 1.7346 + CGAbstractStaticBindingMethod.__init__(self, descriptor, name) 1.7347 + 1.7348 + def generate_code(self): 1.7349 + nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, 1.7350 + self.attr) 1.7351 + checkForArg = CGGeneric(fill( 1.7352 + """ 1.7353 + if (args.length() == 0) { 1.7354 + return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${name} setter"); 1.7355 + } 1.7356 + """, 1.7357 + name=self.attr.identifier.name)) 1.7358 + call = CGSetterCall(self.attr.type, nativeName, self.descriptor, 1.7359 + self.attr) 1.7360 + return CGIndenter(CGList([checkForArg, call])) 1.7361 + 1.7362 + 1.7363 +class CGSpecializedForwardingSetter(CGSpecializedSetter): 1.7364 + """ 1.7365 + A class for generating the code for a specialized attribute setter with 1.7366 + PutForwards that the JIT can call with lower overhead. 1.7367 + """ 1.7368 + def __init__(self, descriptor, attr): 1.7369 + CGSpecializedSetter.__init__(self, descriptor, attr) 1.7370 + 1.7371 + def definition_body(self): 1.7372 + attrName = self.attr.identifier.name 1.7373 + forwardToAttrName = self.attr.getExtendedAttribute("PutForwards")[0] 1.7374 + # JS_GetProperty and JS_SetProperty can only deal with ASCII 1.7375 + assert all(ord(c) < 128 for c in attrName) 1.7376 + assert all(ord(c) < 128 for c in forwardToAttrName) 1.7377 + return indent(fill( 1.7378 + """ 1.7379 + JS::Rooted<JS::Value> v(cx); 1.7380 + if (!JS_GetProperty(cx, obj, "${attr}", &v)) { 1.7381 + return false; 1.7382 + } 1.7383 + 1.7384 + if (!v.isObject()) { 1.7385 + return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "${interface}.${attr}"); 1.7386 + } 1.7387 + 1.7388 + JS::Rooted<JSObject*> targetObj(cx, &v.toObject()); 1.7389 + return JS_SetProperty(cx, targetObj, "${forwardToAttrName}", args[0]); 1.7390 + """, 1.7391 + attr=attrName, 1.7392 + interface=self.descriptor.interface.identifier.name, 1.7393 + forwardToAttrName=forwardToAttrName)) 1.7394 + 1.7395 + 1.7396 +class CGSpecializedReplaceableSetter(CGSpecializedSetter): 1.7397 + """ 1.7398 + A class for generating the code for a specialized attribute setter with 1.7399 + Replaceable that the JIT can call with lower overhead. 1.7400 + """ 1.7401 + def __init__(self, descriptor, attr): 1.7402 + CGSpecializedSetter.__init__(self, descriptor, attr) 1.7403 + 1.7404 + def definition_body(self): 1.7405 + attrName = self.attr.identifier.name 1.7406 + # JS_DefineProperty can only deal with ASCII 1.7407 + assert all(ord(c) < 128 for c in attrName) 1.7408 + return indent('return JS_DefineProperty(cx, obj, "%s", args[0], JSPROP_ENUMERATE);\n' % 1.7409 + attrName) 1.7410 + 1.7411 + 1.7412 +def memberReturnsNewObject(member): 1.7413 + return member.getExtendedAttribute("NewObject") is not None 1.7414 + 1.7415 + 1.7416 +class CGMemberJITInfo(CGThing): 1.7417 + """ 1.7418 + A class for generating the JITInfo for a property that points to 1.7419 + our specialized getter and setter. 1.7420 + """ 1.7421 + def __init__(self, descriptor, member): 1.7422 + self.member = member 1.7423 + self.descriptor = descriptor 1.7424 + 1.7425 + def declare(self): 1.7426 + return "" 1.7427 + 1.7428 + def defineJitInfo(self, infoName, opName, opType, infallible, movable, 1.7429 + aliasSet, hasSlot, slotIndex, returnTypes, args): 1.7430 + """ 1.7431 + aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit. 1.7432 + 1.7433 + args is None if we don't want to output argTypes for some 1.7434 + reason (e.g. we have overloads or we're not a method) and 1.7435 + otherwise an iterable of the arguments for this method. 1.7436 + """ 1.7437 + assert(not movable or aliasSet != "AliasEverything") # Can't move write-aliasing things 1.7438 + assert(not hasSlot or movable) # Things with slots had better be movable 1.7439 + 1.7440 + def jitInfoInitializer(isTypedMethod): 1.7441 + initializer = fill( 1.7442 + """ 1.7443 + { 1.7444 + { ${opName} }, 1.7445 + prototypes::id::${name}, 1.7446 + PrototypeTraits<prototypes::id::${name}>::Depth, 1.7447 + JSJitInfo::${opType}, 1.7448 + JSJitInfo::${aliasSet}, /* aliasSet. Not relevant for setters. */ 1.7449 + ${returnType}, /* returnType. Not relevant for setters. */ 1.7450 + ${isInfallible}, /* isInfallible. False in setters. */ 1.7451 + ${isMovable}, /* isMovable. Not relevant for setters. */ 1.7452 + ${isInSlot}, /* isInSlot. Only relevant for getters. */ 1.7453 + ${isTypedMethod}, /* isTypedMethod. Only relevant for methods. */ 1.7454 + ${slotIndex} /* Reserved slot index, if we're stored in a slot, else 0. */ 1.7455 + } 1.7456 + """, 1.7457 + opName=opName, 1.7458 + name=self.descriptor.name, 1.7459 + opType=opType, 1.7460 + aliasSet=aliasSet, 1.7461 + returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes, 1.7462 + ""), 1.7463 + isInfallible=toStringBool(infallible), 1.7464 + isMovable=toStringBool(movable), 1.7465 + isInSlot=toStringBool(hasSlot), 1.7466 + isTypedMethod=toStringBool(isTypedMethod), 1.7467 + slotIndex=slotIndex) 1.7468 + return initializer.rstrip() 1.7469 + 1.7470 + if args is not None: 1.7471 + argTypes = "%s_argTypes" % infoName 1.7472 + args = [CGMemberJITInfo.getJSArgType(arg.type) for arg in args] 1.7473 + args.append("JSJitInfo::ArgTypeListEnd") 1.7474 + argTypesDecl = ( 1.7475 + "static const JSJitInfo::ArgType %s[] = { %s };\n" % 1.7476 + (argTypes, ", ".join(args))) 1.7477 + return fill( 1.7478 + """ 1.7479 + 1.7480 + $*{argTypesDecl} 1.7481 + static const JSTypedMethodJitInfo ${infoName} = { 1.7482 + ${jitInfo}, 1.7483 + ${argTypes} 1.7484 + }; 1.7485 + """, 1.7486 + argTypesDecl=argTypesDecl, 1.7487 + infoName=infoName, 1.7488 + jitInfo=jitInfoInitializer(True), 1.7489 + argTypes=argTypes) 1.7490 + 1.7491 + return ("\n" 1.7492 + "static const JSJitInfo %s = %s;\n" 1.7493 + % (infoName, jitInfoInitializer(False))) 1.7494 + 1.7495 + def define(self): 1.7496 + if self.member.isAttr(): 1.7497 + getterinfo = ("%s_getterinfo" % self.member.identifier.name) 1.7498 + # We need the cast here because JSJitGetterOp has a "void* self" 1.7499 + # while we have the right type. 1.7500 + getter = ("(JSJitGetterOp)get_%s" % self.member.identifier.name) 1.7501 + getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True) 1.7502 + getterconst = (self.member.getExtendedAttribute("SameObject") or 1.7503 + self.member.getExtendedAttribute("Constant")) 1.7504 + getterpure = getterconst or self.member.getExtendedAttribute("Pure") 1.7505 + if getterconst: 1.7506 + aliasSet = "AliasNone" 1.7507 + elif getterpure: 1.7508 + aliasSet = "AliasDOMSets" 1.7509 + else: 1.7510 + aliasSet = "AliasEverything" 1.7511 + movable = getterpure and getterinfal 1.7512 + 1.7513 + getterinfal = getterinfal and infallibleForMember(self.member, self.member.type, self.descriptor) 1.7514 + isInSlot = self.member.getExtendedAttribute("StoreInSlot") 1.7515 + if isInSlot: 1.7516 + slotIndex = memberReservedSlot(self.member) 1.7517 + # We'll statically assert that this is not too big in 1.7518 + # CGUpdateMemberSlotsMethod 1.7519 + else: 1.7520 + slotIndex = "0" 1.7521 + 1.7522 + result = self.defineJitInfo(getterinfo, getter, "Getter", 1.7523 + getterinfal, movable, aliasSet, 1.7524 + isInSlot, slotIndex, 1.7525 + [self.member.type], None) 1.7526 + if (not self.member.readonly or 1.7527 + self.member.getExtendedAttribute("PutForwards") is not None or 1.7528 + self.member.getExtendedAttribute("Replaceable") is not None): 1.7529 + setterinfo = ("%s_setterinfo" % self.member.identifier.name) 1.7530 + # Actually a JSJitSetterOp, but JSJitGetterOp is first in the 1.7531 + # union. 1.7532 + setter = ("(JSJitGetterOp)set_%s" % self.member.identifier.name) 1.7533 + # Setters are always fallible, since they have to do a typed unwrap. 1.7534 + result += self.defineJitInfo(setterinfo, setter, "Setter", 1.7535 + False, False, "AliasEverything", 1.7536 + False, "0", 1.7537 + [BuiltinTypes[IDLBuiltinType.Types.void]], 1.7538 + None) 1.7539 + return result 1.7540 + if self.member.isMethod(): 1.7541 + methodinfo = ("%s_methodinfo" % self.member.identifier.name) 1.7542 + name = CppKeywords.checkMethodName(self.member.identifier.name) 1.7543 + if self.member.returnsPromise(): 1.7544 + name = CGMethodPromiseWrapper.makeName(name) 1.7545 + # Actually a JSJitMethodOp, but JSJitGetterOp is first in the union. 1.7546 + method = ("(JSJitGetterOp)%s" % name) 1.7547 + methodPure = self.member.getExtendedAttribute("Pure") 1.7548 + 1.7549 + # Methods are infallible if they are infallible, have no arguments 1.7550 + # to unwrap, and have a return type that's infallible to wrap up for 1.7551 + # return. 1.7552 + sigs = self.member.signatures() 1.7553 + if len(sigs) != 1: 1.7554 + # Don't handle overloading. If there's more than one signature, 1.7555 + # one of them must take arguments. 1.7556 + methodInfal = False 1.7557 + args = None 1.7558 + movable = False 1.7559 + else: 1.7560 + sig = sigs[0] 1.7561 + # For pure methods, it's OK to set movable to our notion of 1.7562 + # infallible on the C++ side, without considering argument 1.7563 + # conversions, since argument conversions that can reliably 1.7564 + # throw would be effectful anyway and the jit doesn't move 1.7565 + # effectful things. 1.7566 + hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member) 1.7567 + movable = methodPure and hasInfallibleImpl 1.7568 + # XXXbz can we move the smarts about fallibility due to arg 1.7569 + # conversions into the JIT, using our new args stuff? 1.7570 + if (len(sig[1]) != 0 or 1.7571 + not infallibleForMember(self.member, sig[0], self.descriptor)): 1.7572 + # We have arguments or our return-value boxing can fail 1.7573 + methodInfal = False 1.7574 + else: 1.7575 + methodInfal = hasInfallibleImpl 1.7576 + # For now, only bother to output args if we're pure 1.7577 + if methodPure: 1.7578 + args = sig[1] 1.7579 + else: 1.7580 + args = None 1.7581 + 1.7582 + if args is not None: 1.7583 + aliasSet = "AliasDOMSets" 1.7584 + else: 1.7585 + aliasSet = "AliasEverything" 1.7586 + result = self.defineJitInfo(methodinfo, method, "Method", 1.7587 + methodInfal, movable, aliasSet, False, "0", 1.7588 + [s[0] for s in sigs], args) 1.7589 + return result 1.7590 + raise TypeError("Illegal member type to CGPropertyJITInfo") 1.7591 + 1.7592 + @staticmethod 1.7593 + def getJSReturnTypeTag(t): 1.7594 + if t.nullable(): 1.7595 + # Sometimes it might return null, sometimes not 1.7596 + return "JSVAL_TYPE_UNKNOWN" 1.7597 + if t.isVoid(): 1.7598 + # No return, every time 1.7599 + return "JSVAL_TYPE_UNDEFINED" 1.7600 + if t.isArray(): 1.7601 + # No idea yet 1.7602 + assert False 1.7603 + if t.isSequence(): 1.7604 + return "JSVAL_TYPE_OBJECT" 1.7605 + if t.isMozMap(): 1.7606 + return "JSVAL_TYPE_OBJECT" 1.7607 + if t.isGeckoInterface(): 1.7608 + return "JSVAL_TYPE_OBJECT" 1.7609 + if t.isString(): 1.7610 + return "JSVAL_TYPE_STRING" 1.7611 + if t.isEnum(): 1.7612 + return "JSVAL_TYPE_STRING" 1.7613 + if t.isCallback(): 1.7614 + return "JSVAL_TYPE_OBJECT" 1.7615 + if t.isAny(): 1.7616 + # The whole point is to return various stuff 1.7617 + return "JSVAL_TYPE_UNKNOWN" 1.7618 + if t.isObject(): 1.7619 + return "JSVAL_TYPE_OBJECT" 1.7620 + if t.isSpiderMonkeyInterface(): 1.7621 + return "JSVAL_TYPE_OBJECT" 1.7622 + if t.isUnion(): 1.7623 + u = t.unroll() 1.7624 + if u.hasNullableType: 1.7625 + # Might be null or not 1.7626 + return "JSVAL_TYPE_UNKNOWN" 1.7627 + return reduce(CGMemberJITInfo.getSingleReturnType, 1.7628 + u.flatMemberTypes, "") 1.7629 + if t.isDictionary(): 1.7630 + return "JSVAL_TYPE_OBJECT" 1.7631 + if t.isDate(): 1.7632 + return "JSVAL_TYPE_OBJECT" 1.7633 + if not t.isPrimitive(): 1.7634 + raise TypeError("No idea what type " + str(t) + " is.") 1.7635 + tag = t.tag() 1.7636 + if tag == IDLType.Tags.bool: 1.7637 + return "JSVAL_TYPE_BOOLEAN" 1.7638 + if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, 1.7639 + IDLType.Tags.int16, IDLType.Tags.uint16, 1.7640 + IDLType.Tags.int32]: 1.7641 + return "JSVAL_TYPE_INT32" 1.7642 + if tag in [IDLType.Tags.int64, IDLType.Tags.uint64, 1.7643 + IDLType.Tags.unrestricted_float, IDLType.Tags.float, 1.7644 + IDLType.Tags.unrestricted_double, IDLType.Tags.double]: 1.7645 + # These all use JS_NumberValue, which can return int or double. 1.7646 + # But TI treats "double" as meaning "int or double", so we're 1.7647 + # good to return JSVAL_TYPE_DOUBLE here. 1.7648 + return "JSVAL_TYPE_DOUBLE" 1.7649 + if tag != IDLType.Tags.uint32: 1.7650 + raise TypeError("No idea what type " + str(t) + " is.") 1.7651 + # uint32 is sometimes int and sometimes double. 1.7652 + return "JSVAL_TYPE_DOUBLE" 1.7653 + 1.7654 + @staticmethod 1.7655 + def getSingleReturnType(existingType, t): 1.7656 + type = CGMemberJITInfo.getJSReturnTypeTag(t) 1.7657 + if existingType == "": 1.7658 + # First element of the list; just return its type 1.7659 + return type 1.7660 + 1.7661 + if type == existingType: 1.7662 + return existingType 1.7663 + if ((type == "JSVAL_TYPE_DOUBLE" and 1.7664 + existingType == "JSVAL_TYPE_INT32") or 1.7665 + (existingType == "JSVAL_TYPE_DOUBLE" and 1.7666 + type == "JSVAL_TYPE_INT32")): 1.7667 + # Promote INT32 to DOUBLE as needed 1.7668 + return "JSVAL_TYPE_DOUBLE" 1.7669 + # Different types 1.7670 + return "JSVAL_TYPE_UNKNOWN" 1.7671 + 1.7672 + @staticmethod 1.7673 + def getJSArgType(t): 1.7674 + assert not t.isVoid() 1.7675 + if t.nullable(): 1.7676 + # Sometimes it might return null, sometimes not 1.7677 + return "JSJitInfo::ArgType(JSJitInfo::Null | %s)" % CGMemberJITInfo.getJSArgType(t.inner) 1.7678 + if t.isArray(): 1.7679 + # No idea yet 1.7680 + assert False 1.7681 + if t.isSequence(): 1.7682 + return "JSJitInfo::Object" 1.7683 + if t.isGeckoInterface(): 1.7684 + return "JSJitInfo::Object" 1.7685 + if t.isString(): 1.7686 + return "JSJitInfo::String" 1.7687 + if t.isEnum(): 1.7688 + return "JSJitInfo::String" 1.7689 + if t.isCallback(): 1.7690 + return "JSJitInfo::Object" 1.7691 + if t.isAny(): 1.7692 + # The whole point is to return various stuff 1.7693 + return "JSJitInfo::Any" 1.7694 + if t.isObject(): 1.7695 + return "JSJitInfo::Object" 1.7696 + if t.isSpiderMonkeyInterface(): 1.7697 + return "JSJitInfo::Object" 1.7698 + if t.isUnion(): 1.7699 + u = t.unroll() 1.7700 + type = "JSJitInfo::Null" if u.hasNullableType else "" 1.7701 + return ("JSJitInfo::ArgType(%s)" % 1.7702 + reduce(CGMemberJITInfo.getSingleArgType, 1.7703 + u.flatMemberTypes, type)) 1.7704 + if t.isDictionary(): 1.7705 + return "JSJitInfo::Object" 1.7706 + if t.isDate(): 1.7707 + return "JSJitInfo::Object" 1.7708 + if not t.isPrimitive(): 1.7709 + raise TypeError("No idea what type " + str(t) + " is.") 1.7710 + tag = t.tag() 1.7711 + if tag == IDLType.Tags.bool: 1.7712 + return "JSJitInfo::Boolean" 1.7713 + if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, 1.7714 + IDLType.Tags.int16, IDLType.Tags.uint16, 1.7715 + IDLType.Tags.int32]: 1.7716 + return "JSJitInfo::Integer" 1.7717 + if tag in [IDLType.Tags.int64, IDLType.Tags.uint64, 1.7718 + IDLType.Tags.unrestricted_float, IDLType.Tags.float, 1.7719 + IDLType.Tags.unrestricted_double, IDLType.Tags.double]: 1.7720 + # These all use JS_NumberValue, which can return int or double. 1.7721 + # But TI treats "double" as meaning "int or double", so we're 1.7722 + # good to return JSVAL_TYPE_DOUBLE here. 1.7723 + return "JSJitInfo::Double" 1.7724 + if tag != IDLType.Tags.uint32: 1.7725 + raise TypeError("No idea what type " + str(t) + " is.") 1.7726 + # uint32 is sometimes int and sometimes double. 1.7727 + return "JSJitInfo::Double" 1.7728 + 1.7729 + @staticmethod 1.7730 + def getSingleArgType(existingType, t): 1.7731 + type = CGMemberJITInfo.getJSArgType(t) 1.7732 + if existingType == "": 1.7733 + # First element of the list; just return its type 1.7734 + return type 1.7735 + 1.7736 + if type == existingType: 1.7737 + return existingType 1.7738 + return "%s | %s" % (existingType, type) 1.7739 + 1.7740 + 1.7741 +class CGStaticMethodJitinfo(CGGeneric): 1.7742 + """ 1.7743 + A class for generating the JITInfo for a promise-returning static method. 1.7744 + """ 1.7745 + def __init__(self, method): 1.7746 + CGGeneric.__init__( 1.7747 + self, 1.7748 + "\n" 1.7749 + "static const JSJitInfo %s_methodinfo = {\n" 1.7750 + " { (JSJitGetterOp)%s },\n" 1.7751 + " prototypes::id::_ID_Count, 0, JSJitInfo::StaticMethod,\n" 1.7752 + " JSJitInfo::AliasEverything, JSVAL_TYPE_MISSING, false, false,\n" 1.7753 + " false, false, 0\n" 1.7754 + "};\n" % 1.7755 + (method.identifier.name, method.identifier.name)) 1.7756 + 1.7757 + 1.7758 +def getEnumValueName(value): 1.7759 + # Some enum values can be empty strings. Others might have weird 1.7760 + # characters in them. Deal with the former by returning "_empty", 1.7761 + # deal with possible name collisions from that by throwing if the 1.7762 + # enum value is actually "_empty", and throw on any value 1.7763 + # containing non-ASCII chars for now. Replace all chars other than 1.7764 + # [0-9A-Za-z_] with '_'. 1.7765 + if re.match("[^\x20-\x7E]", value): 1.7766 + raise SyntaxError('Enum value "' + value + '" contains non-ASCII characters') 1.7767 + if re.match("^[0-9]", value): 1.7768 + return '_' + value 1.7769 + value = re.sub(r'[^0-9A-Za-z_]', '_', value) 1.7770 + if re.match("^_[A-Z]|__", value): 1.7771 + raise SyntaxError('Enum value "' + value + '" is reserved by the C++ spec') 1.7772 + if value == "_empty": 1.7773 + raise SyntaxError('"_empty" is not an IDL enum value we support yet') 1.7774 + if value == "": 1.7775 + return "_empty" 1.7776 + return MakeNativeName(value) 1.7777 + 1.7778 + 1.7779 +class CGEnum(CGThing): 1.7780 + def __init__(self, enum): 1.7781 + CGThing.__init__(self) 1.7782 + self.enum = enum 1.7783 + 1.7784 + def stringsNamespace(self): 1.7785 + return self.enum.identifier.name + "Values" 1.7786 + 1.7787 + def nEnumStrings(self): 1.7788 + return len(self.enum.values()) + 1 1.7789 + 1.7790 + def declare(self): 1.7791 + decl = fill( # BOGUS extra newline at top 1.7792 + """ 1.7793 + 1.7794 + MOZ_BEGIN_ENUM_CLASS(${name}, uint32_t) 1.7795 + $*{enums} 1.7796 + MOZ_END_ENUM_CLASS(${name}) 1.7797 + """, 1.7798 + name=self.enum.identifier.name, 1.7799 + enums=",\n".join(map(getEnumValueName, self.enum.values())) + "\n") 1.7800 + strings = CGNamespace(self.stringsNamespace(), 1.7801 + CGGeneric(declare="extern const EnumEntry %s[%d];\n" 1.7802 + % (ENUM_ENTRY_VARIABLE_NAME, self.nEnumStrings()))) 1.7803 + return decl + "\n" + strings.declare() 1.7804 + 1.7805 + def define(self): 1.7806 + strings = fill( # BOGUS extra newline at top 1.7807 + """ 1.7808 + 1.7809 + extern const EnumEntry ${name}[${count}] = { 1.7810 + $*{entries} 1.7811 + { nullptr, 0 } 1.7812 + }; 1.7813 + """, 1.7814 + name=ENUM_ENTRY_VARIABLE_NAME, 1.7815 + count=self.nEnumStrings(), 1.7816 + entries=''.join('{"%s", %d},\n' % (val, len(val)) 1.7817 + for val in self.enum.values())) 1.7818 + # BOGUS - CGNamespace automatically indents; the extra indent() below causes 1.7819 + # the output to be indented 4 spaces. 1.7820 + return CGNamespace(self.stringsNamespace(), 1.7821 + CGGeneric(define=indent(strings))).define() 1.7822 + 1.7823 + def deps(self): 1.7824 + return self.enum.getDeps() 1.7825 + 1.7826 + 1.7827 +def getUnionAccessorSignatureType(type, descriptorProvider): 1.7828 + """ 1.7829 + Returns the types that are used in the getter and setter signatures for 1.7830 + union types 1.7831 + """ 1.7832 + if type.isArray(): 1.7833 + raise TypeError("Can't handle array arguments yet") 1.7834 + 1.7835 + if type.isSequence(): 1.7836 + nullable = type.nullable() 1.7837 + if nullable: 1.7838 + type = type.inner.inner 1.7839 + else: 1.7840 + type = type.inner 1.7841 + # We don't use the returned template here, so it's OK to just pass no 1.7842 + # sourceDescription. 1.7843 + elementInfo = getJSToNativeConversionInfo(type, descriptorProvider, 1.7844 + isMember="Sequence") 1.7845 + typeName = CGTemplatedType("Sequence", elementInfo.declType, 1.7846 + isReference=True) 1.7847 + if nullable: 1.7848 + typeName = CGTemplatedType("Nullable", typeName, isReference=True) 1.7849 + 1.7850 + return typeName 1.7851 + 1.7852 + if type.isUnion(): 1.7853 + typeName = CGGeneric(type.name) 1.7854 + if type.nullable(): 1.7855 + typeName = CGTemplatedType("Nullable", typeName, isReference=True) 1.7856 + 1.7857 + return typeName 1.7858 + 1.7859 + if type.isGeckoInterface(): 1.7860 + descriptor = descriptorProvider.getDescriptor( 1.7861 + type.unroll().inner.identifier.name) 1.7862 + typeName = CGGeneric(descriptor.nativeType) 1.7863 + # Allow null pointers for nullable types and old-binding classes 1.7864 + if type.nullable() or type.unroll().inner.isExternal(): 1.7865 + typeName = CGWrapper(typeName, post="*") 1.7866 + else: 1.7867 + typeName = CGWrapper(typeName, post="&") 1.7868 + return typeName 1.7869 + 1.7870 + if type.isSpiderMonkeyInterface(): 1.7871 + typeName = CGGeneric(type.name) 1.7872 + if type.nullable(): 1.7873 + typeName = CGTemplatedType("Nullable", typeName) 1.7874 + return CGWrapper(typeName, post="&") 1.7875 + 1.7876 + if type.isDOMString(): 1.7877 + return CGGeneric("const nsAString&") 1.7878 + 1.7879 + if type.isByteString(): 1.7880 + return CGGeneric("const nsCString&") 1.7881 + 1.7882 + if type.isEnum(): 1.7883 + if type.nullable(): 1.7884 + raise TypeError("We don't support nullable enumerated arguments or " 1.7885 + "union members yet") 1.7886 + return CGGeneric(type.inner.identifier.name) 1.7887 + 1.7888 + if type.isCallback(): 1.7889 + if type.nullable(): 1.7890 + typeName = "%s*" 1.7891 + else: 1.7892 + typeName = "%s&" 1.7893 + return CGGeneric(typeName % type.unroll().identifier.name) 1.7894 + 1.7895 + if type.isAny(): 1.7896 + return CGGeneric("JS::Value") 1.7897 + 1.7898 + if type.isObject(): 1.7899 + return CGGeneric("JSObject*") 1.7900 + 1.7901 + if type.isDictionary(): 1.7902 + return CGGeneric("const %s&" % type.inner.identifier.name) 1.7903 + 1.7904 + if not type.isPrimitive(): 1.7905 + raise TypeError("Need native type for argument type '%s'" % str(type)) 1.7906 + 1.7907 + typeName = CGGeneric(builtinNames[type.tag()]) 1.7908 + if type.nullable(): 1.7909 + typeName = CGTemplatedType("Nullable", typeName, isReference=True) 1.7910 + return typeName 1.7911 + 1.7912 + 1.7913 +def getUnionTypeTemplateVars(unionType, type, descriptorProvider, 1.7914 + ownsMembers=False): 1.7915 + # For dictionaries and sequences we need to pass None as the failureCode 1.7916 + # for getJSToNativeConversionInfo. 1.7917 + # Also, for dictionaries we would need to handle conversion of 1.7918 + # null/undefined to the dictionary correctly. 1.7919 + if type.isSequence(): 1.7920 + raise TypeError("Can't handle sequences in unions") 1.7921 + 1.7922 + name = getUnionMemberName(type) 1.7923 + 1.7924 + # By the time tryNextCode is invoked, we're guaranteed the union has been 1.7925 + # constructed as some type, since we've been trying to convert into the 1.7926 + # corresponding member. 1.7927 + prefix = "" if ownsMembers else "mUnion." 1.7928 + tryNextCode = ("%sDestroy%s();\n" 1.7929 + "tryNext = true;\n" 1.7930 + "return true;\n" % (prefix, name)) 1.7931 + conversionInfo = getJSToNativeConversionInfo( 1.7932 + type, descriptorProvider, failureCode=tryNextCode, 1.7933 + isDefinitelyObject=not type.isDictionary(), 1.7934 + isMember=("OwningUnion" if ownsMembers else None), 1.7935 + sourceDescription="member of %s" % unionType) 1.7936 + 1.7937 + ctorNeedsCx = conversionInfo.declArgs == "cx" 1.7938 + ctorArgs = "cx" if ctorNeedsCx else "" 1.7939 + 1.7940 + # This is ugly, but UnionMember needs to call a constructor with no 1.7941 + # arguments so the type can't be const. 1.7942 + structType = conversionInfo.declType.define() 1.7943 + if structType.startswith("const "): 1.7944 + structType = structType[6:] 1.7945 + externalType = getUnionAccessorSignatureType(type, descriptorProvider).define() 1.7946 + 1.7947 + if type.isObject(): 1.7948 + if ownsMembers: 1.7949 + body = dedent(""" 1.7950 + MOZ_ASSERT(mType == eUninitialized); 1.7951 + mValue.mObject.SetValue(obj); 1.7952 + mType = eObject; 1.7953 + """) 1.7954 + else: 1.7955 + body = dedent(""" 1.7956 + MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized); 1.7957 + mUnion.mValue.mObject.SetValue(cx, obj); 1.7958 + mUnion.mType = mUnion.eObject; 1.7959 + """) 1.7960 + setter = ClassMethod("SetToObject", "void", 1.7961 + [Argument("JSContext*", "cx"), 1.7962 + Argument("JSObject*", "obj")], 1.7963 + inline=True, bodyInHeader=True, 1.7964 + body=body) 1.7965 + 1.7966 + else: 1.7967 + # Important: we need to not have our declName involve 1.7968 + # maybe-GCing operations. 1.7969 + jsConversion = string.Template(conversionInfo.template).substitute({ 1.7970 + "val": "value", 1.7971 + "mutableVal": "pvalue", 1.7972 + "declName": "memberSlot", 1.7973 + "holderName": "m" + name + "Holder", 1.7974 + }) 1.7975 + jsConversion = fill( 1.7976 + """ 1.7977 + tryNext = false; 1.7978 + { // scope for memberSlot 1.7979 + ${structType}& memberSlot = RawSetAs${name}(${ctorArgs}); 1.7980 + $*{jsConversion} 1.7981 + } 1.7982 + return true; 1.7983 + """, 1.7984 + structType=structType, 1.7985 + name=name, 1.7986 + ctorArgs=ctorArgs, 1.7987 + jsConversion=jsConversion) 1.7988 + 1.7989 + setter = ClassMethod("TrySetTo" + name, "bool", 1.7990 + [Argument("JSContext*", "cx"), 1.7991 + Argument("JS::Handle<JS::Value>", "value"), 1.7992 + Argument("JS::MutableHandle<JS::Value>", "pvalue"), 1.7993 + Argument("bool&", "tryNext")], 1.7994 + inline=not ownsMembers, 1.7995 + bodyInHeader=not ownsMembers, 1.7996 + body=jsConversion) 1.7997 + 1.7998 + return { 1.7999 + "name": name, 1.8000 + "structType": structType, 1.8001 + "externalType": externalType, 1.8002 + "setter": setter, 1.8003 + "holderType": conversionInfo.holderType.define() if conversionInfo.holderType else None, 1.8004 + "ctorArgs": ctorArgs, 1.8005 + "ctorArgList": [Argument("JSContext*", "cx")] if ctorNeedsCx else [] 1.8006 + } 1.8007 + 1.8008 + 1.8009 +class CGUnionStruct(CGThing): 1.8010 + def __init__(self, type, descriptorProvider, ownsMembers=False): 1.8011 + CGThing.__init__(self) 1.8012 + self.type = type.unroll() 1.8013 + self.descriptorProvider = descriptorProvider 1.8014 + self.ownsMembers = ownsMembers 1.8015 + self.struct = self.getStruct() 1.8016 + 1.8017 + def declare(self): 1.8018 + return self.struct.declare() 1.8019 + 1.8020 + def define(self): 1.8021 + return self.struct.define() 1.8022 + 1.8023 + def getStruct(self): 1.8024 + 1.8025 + members = [ClassMember("mType", "Type", body="eUninitialized"), 1.8026 + ClassMember("mValue", "Value")] 1.8027 + ctor = ClassConstructor([], bodyInHeader=True, visibility="public", 1.8028 + explicit=True) 1.8029 + 1.8030 + methods = [] 1.8031 + enumValues = ["eUninitialized"] 1.8032 + toJSValCases = [CGCase("eUninitialized", CGGeneric("return false;\n"))] 1.8033 + destructorCases = [CGCase("eUninitialized", None)] 1.8034 + assignmentCases = [ 1.8035 + CGCase("eUninitialized", 1.8036 + CGGeneric('MOZ_ASSERT(mType == eUninitialized,\n' 1.8037 + ' "We need to destroy ourselves?");\n'))] 1.8038 + traceCases = [] 1.8039 + unionValues = [] 1.8040 + if self.type.hasNullableType: 1.8041 + enumValues.append("eNull") 1.8042 + methods.append(ClassMethod("IsNull", "bool", [], const=True, inline=True, 1.8043 + body="return mType == eNull;\n", 1.8044 + bodyInHeader=True)) 1.8045 + methods.append(ClassMethod("SetNull", "void", [], inline=True, 1.8046 + body=("Uninit();\n" 1.8047 + "mType = eNull;\n"), 1.8048 + bodyInHeader=True)) 1.8049 + destructorCases.append(CGCase("eNull", None)) 1.8050 + assignmentCases.append(CGCase("eNull", 1.8051 + CGGeneric("MOZ_ASSERT(mType == eUninitialized);\n" 1.8052 + "mType = eNull;\n"))) 1.8053 + toJSValCases.append(CGCase("eNull", CGGeneric("rval.setNull();\n" 1.8054 + "return true;\n"))) 1.8055 + 1.8056 + hasObjectType = any(t.isObject() for t in self.type.flatMemberTypes) 1.8057 + for t in self.type.flatMemberTypes: 1.8058 + vars = getUnionTypeTemplateVars(self.type, 1.8059 + t, self.descriptorProvider, 1.8060 + ownsMembers=self.ownsMembers) 1.8061 + if vars["name"] != "Object" or self.ownsMembers: 1.8062 + body = fill( 1.8063 + """ 1.8064 + if (mType == e${name}) { 1.8065 + return mValue.m${name}.Value(); 1.8066 + } 1.8067 + %s 1.8068 + mType = e${name}; 1.8069 + return mValue.m${name}.SetValue(${ctorArgs}); 1.8070 + """, 1.8071 + **vars) 1.8072 + 1.8073 + # bodyInHeader must be false for return values because they own 1.8074 + # their union members and we don't want include headers in 1.8075 + # UnionTypes.h just to call Addref/Release 1.8076 + methods.append(ClassMethod( 1.8077 + "RawSetAs" + vars["name"], 1.8078 + vars["structType"] + "&", 1.8079 + vars["ctorArgList"], 1.8080 + bodyInHeader=not self.ownsMembers, 1.8081 + body=body % "MOZ_ASSERT(mType == eUninitialized);")) 1.8082 + uninit = "Uninit();" 1.8083 + if hasObjectType and not self.ownsMembers: 1.8084 + uninit = 'MOZ_ASSERT(mType != eObject, "This will not play well with Rooted");\n' + uninit 1.8085 + methods.append(ClassMethod( 1.8086 + "SetAs" + vars["name"], 1.8087 + vars["structType"] + "&", 1.8088 + vars["ctorArgList"], 1.8089 + bodyInHeader=not self.ownsMembers, 1.8090 + body=body % uninit)) 1.8091 + if self.ownsMembers: 1.8092 + methods.append(vars["setter"]) 1.8093 + if t.isString(): 1.8094 + methods.append( 1.8095 + ClassMethod("SetStringData", "void", 1.8096 + [Argument("const nsString::char_type*", "aData"), 1.8097 + Argument("nsString::size_type", "aLength")], 1.8098 + inline=True, bodyInHeader=True, 1.8099 + body="RawSetAsString().Assign(aData, aLength);\n")) 1.8100 + 1.8101 + body = fill( 1.8102 + """ 1.8103 + MOZ_ASSERT(Is${name}(), "Wrong type!"); 1.8104 + mValue.m${name}.Destroy(); 1.8105 + mType = eUninitialized; 1.8106 + """, 1.8107 + **vars) 1.8108 + methods.append(ClassMethod("Destroy" + vars["name"], 1.8109 + "void", 1.8110 + [], 1.8111 + visibility="private", 1.8112 + bodyInHeader=not self.ownsMembers, 1.8113 + body=body)) 1.8114 + 1.8115 + body = fill("return mType == e${name};\n", **vars) 1.8116 + methods.append(ClassMethod("Is" + vars["name"], 1.8117 + "bool", 1.8118 + [], 1.8119 + const=True, 1.8120 + bodyInHeader=True, 1.8121 + body=body)) 1.8122 + 1.8123 + body = fill( 1.8124 + """ 1.8125 + MOZ_ASSERT(Is${name}(), "Wrong type!"); 1.8126 + return const_cast<${structType}&>(mValue.m${name}.Value()); 1.8127 + """, 1.8128 + **vars) 1.8129 + if self.ownsMembers: 1.8130 + getterReturnType = "%s&" % vars["structType"] 1.8131 + else: 1.8132 + getterReturnType = vars["externalType"] 1.8133 + methods.append(ClassMethod("GetAs" + vars["name"], 1.8134 + getterReturnType, 1.8135 + [], 1.8136 + const=True, 1.8137 + bodyInHeader=True, 1.8138 + body=body)) 1.8139 + 1.8140 + unionValues.append( 1.8141 + fill("UnionMember<${structType} > m${name}", **vars)) 1.8142 + enumValues.append("e" + vars["name"]) 1.8143 + 1.8144 + toJSValCases.append( 1.8145 + CGCase("e" + vars["name"], 1.8146 + self.getConversionToJS(vars, t))) 1.8147 + destructorCases.append( 1.8148 + CGCase("e" + vars["name"], 1.8149 + CGGeneric("Destroy%s();\n" % vars["name"]))) 1.8150 + assignmentCases.append( 1.8151 + CGCase("e" + vars["name"], 1.8152 + CGGeneric("SetAs%s() = aOther.GetAs%s();\n" % 1.8153 + (vars["name"], vars["name"])))) 1.8154 + if self.ownsMembers and typeNeedsRooting(t): 1.8155 + if t.isObject(): 1.8156 + traceCases.append( 1.8157 + CGCase("e" + vars["name"], 1.8158 + CGGeneric('JS_CallObjectTracer(trc, %s, "%s");\n' % 1.8159 + ("&mValue.m" + vars["name"] + ".Value()", 1.8160 + "mValue.m" + vars["name"])))) 1.8161 + elif t.isDictionary(): 1.8162 + traceCases.append( 1.8163 + CGCase("e" + vars["name"], 1.8164 + CGGeneric("mValue.m%s.Value().TraceDictionary(trc);\n" % 1.8165 + vars["name"]))) 1.8166 + else: 1.8167 + assert t.isSpiderMonkeyInterface() 1.8168 + traceCases.append( 1.8169 + CGCase("e" + vars["name"], 1.8170 + CGGeneric("mValue.m%s.Value().TraceSelf(trc);\n" % 1.8171 + vars["name"]))) 1.8172 + 1.8173 + dtor = CGSwitch("mType", destructorCases).define() 1.8174 + 1.8175 + methods.append(ClassMethod("Uninit", "void", [], 1.8176 + visibility="private", body=dtor, 1.8177 + bodyInHeader=not self.ownsMembers, 1.8178 + inline=not self.ownsMembers)) 1.8179 + 1.8180 + methods.append( 1.8181 + ClassMethod( 1.8182 + "ToJSVal", 1.8183 + "bool", 1.8184 + [ 1.8185 + Argument("JSContext*", "cx"), 1.8186 + Argument("JS::Handle<JSObject*>", "scopeObj"), 1.8187 + Argument("JS::MutableHandle<JS::Value>", "rval") 1.8188 + ], 1.8189 + body=CGSwitch("mType", toJSValCases, 1.8190 + default=CGGeneric("return false;\n")).define(), 1.8191 + const=True)) 1.8192 + 1.8193 + constructors = [ctor] 1.8194 + selfName = CGUnionStruct.unionTypeName(self.type, self.ownsMembers) 1.8195 + if self.ownsMembers: 1.8196 + if traceCases: 1.8197 + # BOGUS blank line in default case 1.8198 + traceBody = CGSwitch("mType", traceCases, 1.8199 + default=CGGeneric("\n")).define() 1.8200 + else: 1.8201 + # BOGUS blank line in method 1.8202 + traceBody = "\n" 1.8203 + methods.append(ClassMethod("TraceUnion", "void", 1.8204 + [Argument("JSTracer*", "trc")], 1.8205 + body=traceBody)) 1.8206 + if CGUnionStruct.isUnionCopyConstructible(self.type): 1.8207 + constructors.append( 1.8208 + ClassConstructor( 1.8209 + [Argument("const %s&" % selfName, "aOther")], 1.8210 + bodyInHeader=True, 1.8211 + visibility="public", 1.8212 + explicit=True, 1.8213 + body="*this = aOther;\n")) 1.8214 + methods.append(ClassMethod( 1.8215 + "operator=", "void", 1.8216 + [Argument("const %s&" % selfName, "aOther")], 1.8217 + body=CGSwitch("aOther.mType", assignmentCases).define())) 1.8218 + disallowCopyConstruction = False 1.8219 + else: 1.8220 + disallowCopyConstruction = True 1.8221 + else: 1.8222 + disallowCopyConstruction = True 1.8223 + 1.8224 + friend = " friend class %sArgument;\n" % str(self.type) if not self.ownsMembers else "" 1.8225 + bases = [ClassBase("AllOwningUnionBase")] if self.ownsMembers else [] 1.8226 + return CGClass(selfName, 1.8227 + bases=bases, 1.8228 + members=members, 1.8229 + constructors=constructors, 1.8230 + methods=methods, 1.8231 + disallowCopyConstruction=disallowCopyConstruction, 1.8232 + extradeclarations=friend, 1.8233 + destructor=ClassDestructor(visibility="public", 1.8234 + body="Uninit();", 1.8235 + bodyInHeader=True), 1.8236 + enums=[ClassEnum("Type", enumValues, visibility="private")], 1.8237 + unions=[ClassUnion("Value", unionValues, visibility="private")]) 1.8238 + 1.8239 + def getConversionToJS(self, templateVars, type): 1.8240 + assert not type.nullable() # flatMemberTypes never has nullable types 1.8241 + val = "mValue.m%(name)s.Value()" % templateVars 1.8242 + wrapCode = wrapForType( 1.8243 + type, self.descriptorProvider, 1.8244 + { 1.8245 + "jsvalRef": "rval", 1.8246 + "jsvalHandle": "rval", 1.8247 + "obj": "scopeObj", 1.8248 + "result": val, 1.8249 + "typedArraysAreStructs": True 1.8250 + }) 1.8251 + return CGGeneric(wrapCode) 1.8252 + 1.8253 + @staticmethod 1.8254 + def isUnionCopyConstructible(type): 1.8255 + return all(isTypeCopyConstructible(t) for t in type.flatMemberTypes) 1.8256 + 1.8257 + @staticmethod 1.8258 + def unionTypeName(type, ownsMembers): 1.8259 + """ 1.8260 + Returns a string name for this known union type. 1.8261 + """ 1.8262 + assert type.isUnion() and not type.nullable() 1.8263 + return ("Owning" if ownsMembers else "") + type.name 1.8264 + 1.8265 + @staticmethod 1.8266 + def unionTypeDecl(type, ownsMembers): 1.8267 + """ 1.8268 + Returns a string for declaring this possibly-nullable union type. 1.8269 + """ 1.8270 + assert type.isUnion() 1.8271 + nullable = type.nullable() 1.8272 + if nullable: 1.8273 + type = type.inner 1.8274 + decl = CGGeneric(CGUnionStruct.unionTypeName(type, ownsMembers)) 1.8275 + if nullable: 1.8276 + decl = CGTemplatedType("Nullable", decl) 1.8277 + return decl.define() 1.8278 + 1.8279 + 1.8280 +class CGUnionConversionStruct(CGThing): 1.8281 + def __init__(self, type, descriptorProvider): 1.8282 + CGThing.__init__(self) 1.8283 + self.type = type.unroll() 1.8284 + self.descriptorProvider = descriptorProvider 1.8285 + 1.8286 + def declare(self): 1.8287 + 1.8288 + structName = str(self.type) 1.8289 + members = [ClassMember("mUnion", structName + "&", 1.8290 + body="const_cast<%s&>(aUnion)" % structName)] 1.8291 + # Argument needs to be a const ref because that's all Maybe<> allows 1.8292 + ctor = ClassConstructor([Argument("const %s&" % structName, "aUnion")], 1.8293 + bodyInHeader=True, 1.8294 + visibility="public", 1.8295 + explicit=True) 1.8296 + methods = [] 1.8297 + 1.8298 + if self.type.hasNullableType: 1.8299 + methods.append(ClassMethod("SetNull", "bool", [], 1.8300 + body=("MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized);\n" 1.8301 + "mUnion.mType = mUnion.eNull;\n" 1.8302 + "return true;\n"), 1.8303 + inline=True, bodyInHeader=True)) 1.8304 + 1.8305 + for t in self.type.flatMemberTypes: 1.8306 + vars = getUnionTypeTemplateVars(self.type, 1.8307 + t, self.descriptorProvider) 1.8308 + methods.append(vars["setter"]) 1.8309 + if vars["name"] != "Object": 1.8310 + body = fill( 1.8311 + """ 1.8312 + MOZ_ASSERT(mUnion.mType == mUnion.eUninitialized); 1.8313 + mUnion.mType = mUnion.e${name}; 1.8314 + return mUnion.mValue.m${name}.SetValue(${ctorArgs}); 1.8315 + """, 1.8316 + **vars) 1.8317 + methods.append(ClassMethod("RawSetAs" + vars["name"], 1.8318 + vars["structType"] + "&", 1.8319 + vars["ctorArgList"], 1.8320 + bodyInHeader=True, 1.8321 + body=body, 1.8322 + visibility="private")) 1.8323 + if t.isString(): 1.8324 + methods.append( 1.8325 + ClassMethod("SetStringData", "void", 1.8326 + [Argument("const nsDependentString::char_type*", "aData"), 1.8327 + Argument("nsDependentString::size_type", "aLength")], 1.8328 + inline=True, bodyInHeader=True, 1.8329 + body="RawSetAsString().SetData(aData, aLength);\n")) 1.8330 + 1.8331 + if vars["holderType"] is not None: 1.8332 + members.append(ClassMember("m%sHolder" % vars["name"], 1.8333 + vars["holderType"])) 1.8334 + 1.8335 + return CGClass(structName + "Argument", 1.8336 + members=members, 1.8337 + constructors=[ctor], 1.8338 + methods=methods, 1.8339 + disallowCopyConstruction=True).declare() 1.8340 + 1.8341 + def define(self): 1.8342 + return "\n" 1.8343 + 1.8344 + 1.8345 +class ClassItem: 1.8346 + """ Use with CGClass """ 1.8347 + def __init__(self, name, visibility): 1.8348 + self.name = name 1.8349 + self.visibility = visibility 1.8350 + 1.8351 + def declare(self, cgClass): 1.8352 + assert False 1.8353 + 1.8354 + def define(self, cgClass): 1.8355 + assert False 1.8356 + 1.8357 + 1.8358 +class ClassBase(ClassItem): 1.8359 + def __init__(self, name, visibility='public'): 1.8360 + ClassItem.__init__(self, name, visibility) 1.8361 + 1.8362 + def declare(self, cgClass): 1.8363 + return '%s %s' % (self.visibility, self.name) 1.8364 + 1.8365 + def define(self, cgClass): 1.8366 + # Only in the header 1.8367 + return '' 1.8368 + 1.8369 + 1.8370 +class ClassMethod(ClassItem): 1.8371 + def __init__(self, name, returnType, args, inline=False, static=False, 1.8372 + virtual=False, const=False, bodyInHeader=False, 1.8373 + templateArgs=None, visibility='public', body=None, 1.8374 + breakAfterReturnDecl="\n", 1.8375 + breakAfterSelf="\n", override=False): 1.8376 + """ 1.8377 + override indicates whether to flag the method as MOZ_OVERRIDE 1.8378 + """ 1.8379 + assert not override or virtual 1.8380 + assert not (override and static) 1.8381 + self.returnType = returnType 1.8382 + self.args = args 1.8383 + self.inline = inline or bodyInHeader 1.8384 + self.static = static 1.8385 + self.virtual = virtual 1.8386 + self.const = const 1.8387 + self.bodyInHeader = bodyInHeader 1.8388 + self.templateArgs = templateArgs 1.8389 + self.body = body 1.8390 + self.breakAfterReturnDecl = breakAfterReturnDecl 1.8391 + self.breakAfterSelf = breakAfterSelf 1.8392 + self.override = override 1.8393 + ClassItem.__init__(self, name, visibility) 1.8394 + 1.8395 + def getDecorators(self, declaring): 1.8396 + decorators = [] 1.8397 + if self.inline: 1.8398 + decorators.append('inline') 1.8399 + if declaring: 1.8400 + if self.static: 1.8401 + decorators.append('static') 1.8402 + if self.virtual: 1.8403 + decorators.append('virtual') 1.8404 + if decorators: 1.8405 + return ' '.join(decorators) + ' ' 1.8406 + return '' 1.8407 + 1.8408 + def getBody(self): 1.8409 + # Override me or pass a string to constructor 1.8410 + assert self.body is not None 1.8411 + return self.body 1.8412 + 1.8413 + def declare(self, cgClass): 1.8414 + templateClause = ('template <%s>\n' % ', '.join(self.templateArgs) 1.8415 + if self.bodyInHeader and self.templateArgs else '') 1.8416 + args = ', '.join([a.declare() for a in self.args]) 1.8417 + if self.bodyInHeader: 1.8418 + body = indent(self.getBody()) 1.8419 + body = '\n{\n' + body + '}\n' 1.8420 + else: 1.8421 + body = ';\n' 1.8422 + 1.8423 + return fill( 1.8424 + "${templateClause}${decorators}${returnType}${breakAfterReturnDecl}" 1.8425 + "${name}(${args})${const}${override}${body}" 1.8426 + "${breakAfterSelf}", 1.8427 + templateClause=templateClause, 1.8428 + decorators=self.getDecorators(True), 1.8429 + returnType=self.returnType, 1.8430 + breakAfterReturnDecl=self.breakAfterReturnDecl, 1.8431 + name=self.name, 1.8432 + args=args, 1.8433 + const=' const' if self.const else '', 1.8434 + override=' MOZ_OVERRIDE' if self.override else '', 1.8435 + body=body, 1.8436 + breakAfterSelf=self.breakAfterSelf) 1.8437 + 1.8438 + def define(self, cgClass): 1.8439 + if self.bodyInHeader: 1.8440 + return '' 1.8441 + 1.8442 + templateArgs = cgClass.templateArgs 1.8443 + if templateArgs: 1.8444 + if cgClass.templateSpecialization: 1.8445 + templateArgs = \ 1.8446 + templateArgs[len(cgClass.templateSpecialization):] 1.8447 + 1.8448 + if templateArgs: 1.8449 + templateClause = \ 1.8450 + 'template <%s>\n' % ', '.join([str(a) for a in templateArgs]) 1.8451 + else: 1.8452 + templateClause = '' 1.8453 + 1.8454 + return fill( 1.8455 + """ 1.8456 + ${templateClause}${decorators}${returnType} 1.8457 + ${className}::${name}(${args})${const} 1.8458 + { 1.8459 + $*{body} 1.8460 + } 1.8461 + """, 1.8462 + templateClause=templateClause, 1.8463 + decorators=self.getDecorators(False), 1.8464 + returnType=self.returnType, 1.8465 + className=cgClass.getNameString(), 1.8466 + name=self.name, 1.8467 + args=', '.join([a.define() for a in self.args]), 1.8468 + const=' const' if self.const else '', 1.8469 + body=self.getBody()) 1.8470 + 1.8471 + 1.8472 +class ClassUsingDeclaration(ClassItem): 1.8473 + """ 1.8474 + Used for importing a name from a base class into a CGClass 1.8475 + 1.8476 + baseClass is the name of the base class to import the name from 1.8477 + 1.8478 + name is the name to import 1.8479 + 1.8480 + visibility determines the visibility of the name (public, 1.8481 + protected, private), defaults to public. 1.8482 + """ 1.8483 + def __init__(self, baseClass, name, visibility='public'): 1.8484 + self.baseClass = baseClass 1.8485 + ClassItem.__init__(self, name, visibility) 1.8486 + 1.8487 + def declare(self, cgClass): 1.8488 + return "using %s::%s;\n\n" % (self.baseClass, self.name) 1.8489 + 1.8490 + def define(self, cgClass): 1.8491 + return '' 1.8492 + 1.8493 + 1.8494 +class ClassConstructor(ClassItem): 1.8495 + """ 1.8496 + Used for adding a constructor to a CGClass. 1.8497 + 1.8498 + args is a list of Argument objects that are the arguments taken by the 1.8499 + constructor. 1.8500 + 1.8501 + inline should be True if the constructor should be marked inline. 1.8502 + 1.8503 + bodyInHeader should be True if the body should be placed in the class 1.8504 + declaration in the header. 1.8505 + 1.8506 + visibility determines the visibility of the constructor (public, 1.8507 + protected, private), defaults to private. 1.8508 + 1.8509 + explicit should be True if the constructor should be marked explicit. 1.8510 + 1.8511 + baseConstructors is a list of strings containing calls to base constructors, 1.8512 + defaults to None. 1.8513 + 1.8514 + body contains a string with the code for the constructor, defaults to empty. 1.8515 + """ 1.8516 + def __init__(self, args, inline=False, bodyInHeader=False, 1.8517 + visibility="private", explicit=False, baseConstructors=None, 1.8518 + body=""): 1.8519 + self.args = args 1.8520 + self.inline = inline or bodyInHeader 1.8521 + self.bodyInHeader = bodyInHeader 1.8522 + self.explicit = explicit 1.8523 + self.baseConstructors = baseConstructors or [] 1.8524 + self.body = body 1.8525 + ClassItem.__init__(self, None, visibility) 1.8526 + 1.8527 + def getDecorators(self, declaring): 1.8528 + decorators = [] 1.8529 + if self.explicit: 1.8530 + decorators.append('explicit') 1.8531 + if self.inline and declaring: 1.8532 + decorators.append('inline') 1.8533 + if decorators: 1.8534 + return ' '.join(decorators) + ' ' 1.8535 + return '' 1.8536 + 1.8537 + def getInitializationList(self, cgClass): 1.8538 + items = [str(c) for c in self.baseConstructors] 1.8539 + for m in cgClass.members: 1.8540 + if not m.static: 1.8541 + initialize = m.body 1.8542 + if initialize: 1.8543 + items.append(m.name + "(" + initialize + ")") 1.8544 + 1.8545 + if len(items) > 0: 1.8546 + return '\n : ' + ',\n '.join(items) 1.8547 + return '' 1.8548 + 1.8549 + def getBody(self): 1.8550 + return self.body 1.8551 + 1.8552 + def declare(self, cgClass): 1.8553 + args = ', '.join([a.declare() for a in self.args]) 1.8554 + if self.bodyInHeader: 1.8555 + body = self.getInitializationList(cgClass) + '\n{\n' + indent(self.getBody()) + '}\n' 1.8556 + else: 1.8557 + body = ';\n' 1.8558 + 1.8559 + return fill( 1.8560 + "${decorators}${className}(${args})${body}\n", 1.8561 + decorators=self.getDecorators(True), 1.8562 + className=cgClass.getNameString(), 1.8563 + args=args, 1.8564 + body=body) 1.8565 + 1.8566 + def define(self, cgClass): 1.8567 + if self.bodyInHeader: 1.8568 + return '' 1.8569 + 1.8570 + return fill( 1.8571 + """ 1.8572 + ${decorators} 1.8573 + ${className}::${className}(${args})${initializationList} 1.8574 + { 1.8575 + $*{body} 1.8576 + } 1.8577 + """, 1.8578 + decorators=self.getDecorators(False), 1.8579 + className=cgClass.getNameString(), 1.8580 + args=', '.join([a.define() for a in self.args]), 1.8581 + initializationList=self.getInitializationList(cgClass), 1.8582 + body=self.getBody()) 1.8583 + 1.8584 + 1.8585 +class ClassDestructor(ClassItem): 1.8586 + """ 1.8587 + Used for adding a destructor to a CGClass. 1.8588 + 1.8589 + inline should be True if the destructor should be marked inline. 1.8590 + 1.8591 + bodyInHeader should be True if the body should be placed in the class 1.8592 + declaration in the header. 1.8593 + 1.8594 + visibility determines the visibility of the destructor (public, 1.8595 + protected, private), defaults to private. 1.8596 + 1.8597 + body contains a string with the code for the destructor, defaults to empty. 1.8598 + 1.8599 + virtual determines whether the destructor is virtual, defaults to False. 1.8600 + """ 1.8601 + def __init__(self, inline=False, bodyInHeader=False, 1.8602 + visibility="private", body='', virtual=False): 1.8603 + self.inline = inline or bodyInHeader 1.8604 + self.bodyInHeader = bodyInHeader 1.8605 + self.body = body 1.8606 + self.virtual = virtual 1.8607 + ClassItem.__init__(self, None, visibility) 1.8608 + 1.8609 + def getDecorators(self, declaring): 1.8610 + decorators = [] 1.8611 + if self.virtual and declaring: 1.8612 + decorators.append('virtual') 1.8613 + if self.inline and declaring: 1.8614 + decorators.append('inline') 1.8615 + if decorators: 1.8616 + return ' '.join(decorators) + ' ' 1.8617 + return '' 1.8618 + 1.8619 + def getBody(self): 1.8620 + return self.body 1.8621 + 1.8622 + def declare(self, cgClass): 1.8623 + if self.bodyInHeader: 1.8624 + body = '\n{\n' + indent(self.getBody()) + '}\n' 1.8625 + else: 1.8626 + body = ';\n' 1.8627 + 1.8628 + return fill( 1.8629 + "${decorators}~${className}()${body}\n", 1.8630 + decorators=self.getDecorators(True), 1.8631 + className=cgClass.getNameString(), 1.8632 + body=body) 1.8633 + 1.8634 + def define(self, cgClass): 1.8635 + if self.bodyInHeader: 1.8636 + return '' 1.8637 + return fill( 1.8638 + """ 1.8639 + ${decorators} 1.8640 + ${className}::~${className}() 1.8641 + { 1.8642 + $*{body} 1.8643 + } 1.8644 + """, 1.8645 + decorators=self.getDecorators(False), 1.8646 + className=cgClass.getNameString(), 1.8647 + body=self.getBody() or "\n") # BOGUS extra blank line if empty 1.8648 + 1.8649 + 1.8650 +class ClassMember(ClassItem): 1.8651 + def __init__(self, name, type, visibility="private", static=False, 1.8652 + body=None): 1.8653 + self.type = type 1.8654 + self.static = static 1.8655 + self.body = body 1.8656 + ClassItem.__init__(self, name, visibility) 1.8657 + 1.8658 + def declare(self, cgClass): 1.8659 + return '%s%s %s;\n' % ('static ' if self.static else '', self.type, 1.8660 + self.name) 1.8661 + 1.8662 + def define(self, cgClass): 1.8663 + if not self.static: 1.8664 + return '' 1.8665 + if self.body: 1.8666 + body = " = " + self.body 1.8667 + else: 1.8668 + body = "" 1.8669 + return '%s %s::%s%s;\n' % (self.type, cgClass.getNameString(), 1.8670 + self.name, body) 1.8671 + 1.8672 + 1.8673 +class ClassTypedef(ClassItem): 1.8674 + def __init__(self, name, type, visibility="public"): 1.8675 + self.type = type 1.8676 + ClassItem.__init__(self, name, visibility) 1.8677 + 1.8678 + def declare(self, cgClass): 1.8679 + return 'typedef %s %s;\n' % (self.type, self.name) 1.8680 + 1.8681 + def define(self, cgClass): 1.8682 + # Only goes in the header 1.8683 + return '' 1.8684 + 1.8685 + 1.8686 +class ClassEnum(ClassItem): 1.8687 + def __init__(self, name, entries, values=None, visibility="public"): 1.8688 + self.entries = entries 1.8689 + self.values = values 1.8690 + ClassItem.__init__(self, name, visibility) 1.8691 + 1.8692 + def declare(self, cgClass): 1.8693 + entries = [] 1.8694 + for i in range(0, len(self.entries)): 1.8695 + if not self.values or i >= len(self.values): 1.8696 + entry = '%s' % self.entries[i] 1.8697 + else: 1.8698 + entry = '%s = %s' % (self.entries[i], self.values[i]) 1.8699 + entries.append(entry) 1.8700 + name = '' if not self.name else ' ' + self.name 1.8701 + return 'enum%s\n{\n%s\n};\n' % (name, indent(',\n'.join(entries))) 1.8702 + 1.8703 + def define(self, cgClass): 1.8704 + # Only goes in the header 1.8705 + return '' 1.8706 + 1.8707 + 1.8708 +class ClassUnion(ClassItem): 1.8709 + def __init__(self, name, entries, visibility="public"): 1.8710 + self.entries = [entry + ";\n" for entry in entries] 1.8711 + ClassItem.__init__(self, name, visibility) 1.8712 + 1.8713 + def declare(self, cgClass): 1.8714 + return "union %s\n{\n%s\n};\n" % (self.name, indent(''.join(self.entries))) 1.8715 + 1.8716 + def define(self, cgClass): 1.8717 + # Only goes in the header 1.8718 + return '' 1.8719 + 1.8720 + 1.8721 +class CGClass(CGThing): 1.8722 + def __init__(self, name, bases=[], members=[], constructors=[], 1.8723 + destructor=None, methods=[], 1.8724 + typedefs=[], enums=[], unions=[], templateArgs=[], 1.8725 + templateSpecialization=[], isStruct=False, 1.8726 + disallowCopyConstruction=False, indent='', 1.8727 + decorators='', 1.8728 + extradeclarations='', 1.8729 + extradefinitions=''): 1.8730 + CGThing.__init__(self) 1.8731 + self.name = name 1.8732 + self.bases = bases 1.8733 + self.members = members 1.8734 + self.constructors = constructors 1.8735 + # We store our single destructor in a list, since all of our 1.8736 + # code wants lists of members. 1.8737 + self.destructors = [destructor] if destructor else [] 1.8738 + self.methods = methods 1.8739 + self.typedefs = typedefs 1.8740 + self.enums = enums 1.8741 + self.unions = unions 1.8742 + self.templateArgs = templateArgs 1.8743 + self.templateSpecialization = templateSpecialization 1.8744 + self.isStruct = isStruct 1.8745 + self.disallowCopyConstruction = disallowCopyConstruction 1.8746 + self.indent = indent 1.8747 + self.defaultVisibility = 'public' if isStruct else 'private' 1.8748 + self.decorators = decorators 1.8749 + self.extradeclarations = extradeclarations 1.8750 + self.extradefinitions = extradefinitions 1.8751 + 1.8752 + def getNameString(self): 1.8753 + className = self.name 1.8754 + if self.templateSpecialization: 1.8755 + className += '<%s>' % ', '.join([str(a) 1.8756 + for a in self.templateSpecialization]) 1.8757 + return className 1.8758 + 1.8759 + def declare(self): 1.8760 + result = '' 1.8761 + if self.templateArgs: 1.8762 + templateArgs = [a.declare() for a in self.templateArgs] 1.8763 + templateArgs = templateArgs[len(self.templateSpecialization):] 1.8764 + result += ('template <%s>\n' % 1.8765 + ','.join([str(a) for a in templateArgs])) 1.8766 + 1.8767 + type = 'struct' if self.isStruct else 'class' 1.8768 + 1.8769 + if self.templateSpecialization: 1.8770 + specialization = \ 1.8771 + '<%s>' % ', '.join([str(a) for a in self.templateSpecialization]) 1.8772 + else: 1.8773 + specialization = '' 1.8774 + 1.8775 + myself = '%s %s%s' % (type, self.name, specialization) 1.8776 + if self.decorators != '': 1.8777 + myself += " " + self.decorators 1.8778 + result += myself 1.8779 + 1.8780 + if self.bases: 1.8781 + inherit = ' : ' 1.8782 + result += inherit 1.8783 + # Grab our first base 1.8784 + baseItems = [CGGeneric(b.declare(self)) for b in self.bases] 1.8785 + bases = baseItems[:1] 1.8786 + # Indent the rest 1.8787 + bases.extend(CGIndenter(b, len(myself) + len(inherit)) 1.8788 + for b in baseItems[1:]) 1.8789 + result += ",\n".join(b.define() for b in bases) 1.8790 + 1.8791 + result += '\n{\n' 1.8792 + 1.8793 + result += self.extradeclarations 1.8794 + 1.8795 + def declareMembers(cgClass, memberList, defaultVisibility): 1.8796 + members = {'private': [], 'protected': [], 'public': []} 1.8797 + 1.8798 + for member in memberList: 1.8799 + members[member.visibility].append(member) 1.8800 + 1.8801 + if defaultVisibility == 'public': 1.8802 + order = ['public', 'protected', 'private'] 1.8803 + else: 1.8804 + order = ['private', 'protected', 'public'] 1.8805 + 1.8806 + result = '' 1.8807 + 1.8808 + lastVisibility = defaultVisibility 1.8809 + for visibility in order: 1.8810 + list = members[visibility] 1.8811 + if list: 1.8812 + if visibility != lastVisibility: 1.8813 + result += visibility + ':\n' 1.8814 + for member in list: 1.8815 + result += indent(member.declare(cgClass)) 1.8816 + lastVisibility = visibility 1.8817 + return (result, lastVisibility) 1.8818 + 1.8819 + if self.disallowCopyConstruction: 1.8820 + class DisallowedCopyConstructor(object): 1.8821 + def __init__(self): 1.8822 + self.visibility = "private" 1.8823 + 1.8824 + def declare(self, cgClass): 1.8825 + name = cgClass.getNameString() 1.8826 + return ("%s(const %s&) MOZ_DELETE;\n" 1.8827 + "void operator=(const %s) MOZ_DELETE;\n" % (name, name, name)) 1.8828 + 1.8829 + disallowedCopyConstructors = [DisallowedCopyConstructor()] 1.8830 + else: 1.8831 + disallowedCopyConstructors = [] 1.8832 + 1.8833 + order = [self.enums, self.unions, 1.8834 + self.typedefs, self.members, 1.8835 + self.constructors + disallowedCopyConstructors, 1.8836 + self.destructors, self.methods] 1.8837 + 1.8838 + lastVisibility = self.defaultVisibility 1.8839 + pieces = [] 1.8840 + for memberList in order: 1.8841 + code, lastVisibility = declareMembers(self, memberList, lastVisibility) 1.8842 + 1.8843 + if code: 1.8844 + code = code.rstrip() + "\n" # remove extra blank lines at the end 1.8845 + pieces.append(code) 1.8846 + 1.8847 + result += '\n'.join(pieces) 1.8848 + result += '};\n' 1.8849 + result = indent(result, len(self.indent)) 1.8850 + return result 1.8851 + 1.8852 + def define(self): 1.8853 + def defineMembers(cgClass, memberList, itemCount, separator=''): 1.8854 + result = '' 1.8855 + for member in memberList: 1.8856 + if itemCount != 0: 1.8857 + result = result + separator 1.8858 + definition = member.define(cgClass) 1.8859 + if definition: 1.8860 + # Member variables would only produce empty lines here. 1.8861 + result += definition 1.8862 + itemCount += 1 1.8863 + return (result, itemCount) 1.8864 + 1.8865 + order = [(self.members, ''), (self.constructors, '\n'), 1.8866 + (self.destructors, '\n'), (self.methods, '\n')] 1.8867 + 1.8868 + result = self.extradefinitions 1.8869 + itemCount = 0 1.8870 + for memberList, separator in order: 1.8871 + memberString, itemCount = defineMembers(self, memberList, 1.8872 + itemCount, separator) 1.8873 + result = result + memberString 1.8874 + return result 1.8875 + 1.8876 + 1.8877 +class CGResolveOwnProperty(CGAbstractStaticMethod): 1.8878 + def __init__(self, descriptor): 1.8879 + args = [Argument('JSContext*', 'cx'), 1.8880 + Argument('JS::Handle<JSObject*>', 'wrapper'), 1.8881 + Argument('JS::Handle<JSObject*>', 'obj'), 1.8882 + Argument('JS::Handle<jsid>', 'id'), 1.8883 + Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'), 1.8884 + ] 1.8885 + CGAbstractStaticMethod.__init__(self, descriptor, "ResolveOwnProperty", 1.8886 + "bool", args) 1.8887 + 1.8888 + def definition_body(self): 1.8889 + # BOGUS extra blank line at end of function 1.8890 + return " return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc);\n\n" 1.8891 + 1.8892 + 1.8893 +class CGResolveOwnPropertyViaNewresolve(CGAbstractBindingMethod): 1.8894 + """ 1.8895 + An implementation of Xray ResolveOwnProperty stuff for things that have a 1.8896 + newresolve hook. 1.8897 + """ 1.8898 + def __init__(self, descriptor): 1.8899 + args = [Argument('JSContext*', 'cx'), 1.8900 + Argument('JS::Handle<JSObject*>', 'wrapper'), 1.8901 + Argument('JS::Handle<JSObject*>', 'obj'), 1.8902 + Argument('JS::Handle<jsid>', 'id'), 1.8903 + Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc')] 1.8904 + CGAbstractBindingMethod.__init__(self, descriptor, 1.8905 + "ResolveOwnPropertyViaNewresolve", 1.8906 + args, getThisObj="", 1.8907 + callArgs="") 1.8908 + 1.8909 + def generate_code(self): 1.8910 + return CGGeneric(indent(dedent(""" 1.8911 + { 1.8912 + // Since we're dealing with an Xray, do the resolve on the 1.8913 + // underlying object first. That gives it a chance to 1.8914 + // define properties on the actual object as needed, and 1.8915 + // then use the fact that it created the objects as a flag 1.8916 + // to avoid re-resolving the properties if someone deletes 1.8917 + // them. 1.8918 + JSAutoCompartment ac(cx, obj); 1.8919 + JS::Rooted<JSPropertyDescriptor> objDesc(cx); 1.8920 + if (!self->DoNewResolve(cx, obj, id, &objDesc)) { 1.8921 + return false; 1.8922 + } 1.8923 + // If desc.value() is undefined, then the DoNewResolve call 1.8924 + // has already defined the property on the object. Don't 1.8925 + // try to also define it. 1.8926 + if (objDesc.object() && 1.8927 + !objDesc.value().isUndefined() && 1.8928 + !JS_DefinePropertyById(cx, obj, id, objDesc.value(), 1.8929 + objDesc.getter(), objDesc.setter(), 1.8930 + objDesc.attributes())) { 1.8931 + return false; 1.8932 + } 1.8933 + } 1.8934 + return self->DoNewResolve(cx, wrapper, id, desc); 1.8935 + """))) 1.8936 + 1.8937 + 1.8938 +class CGEnumerateOwnProperties(CGAbstractStaticMethod): 1.8939 + def __init__(self, descriptor): 1.8940 + args = [Argument('JSContext*', 'cx'), 1.8941 + Argument('JS::Handle<JSObject*>', 'wrapper'), 1.8942 + Argument('JS::Handle<JSObject*>', 'obj'), 1.8943 + Argument('JS::AutoIdVector&', 'props')] 1.8944 + CGAbstractStaticMethod.__init__(self, descriptor, 1.8945 + "EnumerateOwnProperties", "bool", args) 1.8946 + 1.8947 + def definition_body(self): 1.8948 + # BOGUS extra newline 1.8949 + return " return js::GetProxyHandler(obj)->getOwnPropertyNames(cx, wrapper, props);\n\n" 1.8950 + 1.8951 + 1.8952 +class CGEnumerateOwnPropertiesViaGetOwnPropertyNames(CGAbstractBindingMethod): 1.8953 + """ 1.8954 + An implementation of Xray EnumerateOwnProperties stuff for things 1.8955 + that have a newresolve hook. 1.8956 + """ 1.8957 + def __init__(self, descriptor): 1.8958 + args = [Argument('JSContext*', 'cx'), 1.8959 + Argument('JS::Handle<JSObject*>', 'wrapper'), 1.8960 + Argument('JS::Handle<JSObject*>', 'obj'), 1.8961 + Argument('JS::AutoIdVector&', 'props')] 1.8962 + CGAbstractBindingMethod.__init__(self, descriptor, 1.8963 + "EnumerateOwnPropertiesViaGetOwnPropertyNames", 1.8964 + args, getThisObj="", 1.8965 + callArgs="") 1.8966 + 1.8967 + def generate_code(self): 1.8968 + return CGIndenter(CGGeneric(dedent(""" 1.8969 + nsAutoTArray<nsString, 8> names; 1.8970 + ErrorResult rv; 1.8971 + self->GetOwnPropertyNames(cx, names, rv); 1.8972 + rv.WouldReportJSException(); 1.8973 + if (rv.Failed()) { 1.8974 + return ThrowMethodFailedWithDetails(cx, rv, "%s", "enumerate"); 1.8975 + } 1.8976 + // OK to pass null as "proxy" because it's ignored if 1.8977 + // shadowPrototypeProperties is true 1.8978 + return AppendNamedPropertyIds(cx, JS::NullPtr(), names, true, props); 1.8979 + """))) 1.8980 + 1.8981 + 1.8982 +class CGPrototypeTraitsClass(CGClass): 1.8983 + def __init__(self, descriptor, indent=''): 1.8984 + templateArgs = [Argument('prototypes::ID', 'PrototypeID')] 1.8985 + templateSpecialization = ['prototypes::id::' + descriptor.name] 1.8986 + enums = [ClassEnum('', ['Depth'], 1.8987 + [descriptor.interface.inheritanceDepth()])] 1.8988 + CGClass.__init__(self, 'PrototypeTraits', indent=indent, 1.8989 + templateArgs=templateArgs, 1.8990 + templateSpecialization=templateSpecialization, 1.8991 + enums=enums, isStruct=True) 1.8992 + 1.8993 + def deps(self): 1.8994 + return set() 1.8995 + 1.8996 + 1.8997 +class CGClassForwardDeclare(CGThing): 1.8998 + def __init__(self, name, isStruct=False): 1.8999 + CGThing.__init__(self) 1.9000 + self.name = name 1.9001 + self.isStruct = isStruct 1.9002 + 1.9003 + def declare(self): 1.9004 + type = 'struct' if self.isStruct else 'class' 1.9005 + return '%s %s;\n' % (type, self.name) 1.9006 + 1.9007 + def define(self): 1.9008 + # Header only 1.9009 + return '' 1.9010 + 1.9011 + def deps(self): 1.9012 + return set() 1.9013 + 1.9014 + 1.9015 +class CGProxySpecialOperation(CGPerSignatureCall): 1.9016 + """ 1.9017 + Base class for classes for calling an indexed or named special operation 1.9018 + (don't use this directly, use the derived classes below). 1.9019 + 1.9020 + If checkFound is False, will just assert that the prop is found instead of 1.9021 + checking that it is before wrapping the value. 1.9022 + """ 1.9023 + def __init__(self, descriptor, operation, checkFound=True, argumentMutableValue=None): 1.9024 + self.checkFound = checkFound 1.9025 + 1.9026 + nativeName = MakeNativeName(descriptor.binaryNames.get(operation, operation)) 1.9027 + operation = descriptor.operations[operation] 1.9028 + assert len(operation.signatures()) == 1 1.9029 + signature = operation.signatures()[0] 1.9030 + 1.9031 + returnType, arguments = signature 1.9032 + 1.9033 + # We pass len(arguments) as the final argument so that the 1.9034 + # CGPerSignatureCall won't do any argument conversion of its own. 1.9035 + CGPerSignatureCall.__init__(self, returnType, arguments, nativeName, 1.9036 + False, descriptor, operation, 1.9037 + len(arguments)) 1.9038 + 1.9039 + if operation.isSetter() or operation.isCreator(): 1.9040 + # arguments[0] is the index or name of the item that we're setting. 1.9041 + argument = arguments[1] 1.9042 + info = getJSToNativeConversionInfo( 1.9043 + argument.type, descriptor, 1.9044 + treatNullAs=argument.treatNullAs, 1.9045 + sourceDescription=("value being assigned to %s setter" % 1.9046 + descriptor.interface.identifier.name)) 1.9047 + if argumentMutableValue is None: 1.9048 + argumentMutableValue = "desc.value()" 1.9049 + templateValues = { 1.9050 + "declName": argument.identifier.name, 1.9051 + "holderName": argument.identifier.name + "_holder", 1.9052 + "val": argumentMutableValue, 1.9053 + "mutableVal": argumentMutableValue, 1.9054 + "obj": "obj" 1.9055 + } 1.9056 + self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues)) 1.9057 + elif operation.isGetter() or operation.isDeleter(): 1.9058 + self.cgRoot.prepend(CGGeneric("bool found;\n")) 1.9059 + 1.9060 + def getArguments(self): 1.9061 + args = [(a, a.identifier.name) for a in self.arguments] 1.9062 + if self.idlNode.isGetter() or self.idlNode.isDeleter(): 1.9063 + args.append((FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean], 1.9064 + self.idlNode), 1.9065 + "found")) 1.9066 + return args 1.9067 + 1.9068 + def wrap_return_value(self): 1.9069 + if not self.idlNode.isGetter() or self.templateValues is None: 1.9070 + return "" 1.9071 + 1.9072 + wrap = CGGeneric(wrapForType(self.returnType, self.descriptor, self.templateValues)) 1.9073 + if self.checkFound: 1.9074 + wrap = CGIfWrapper(wrap, "found") 1.9075 + else: 1.9076 + wrap = CGList([CGGeneric("MOZ_ASSERT(found);\n"), wrap]) 1.9077 + return "\n" + wrap.define() 1.9078 + 1.9079 + 1.9080 +class CGProxyIndexedOperation(CGProxySpecialOperation): 1.9081 + """ 1.9082 + Class to generate a call to an indexed operation. 1.9083 + 1.9084 + If doUnwrap is False, the caller is responsible for making sure a variable 1.9085 + named 'self' holds the C++ object somewhere where the code we generate 1.9086 + will see it. 1.9087 + 1.9088 + If checkFound is False, will just assert that the prop is found instead of 1.9089 + checking that it is before wrapping the value. 1.9090 + """ 1.9091 + def __init__(self, descriptor, name, doUnwrap=True, checkFound=True, 1.9092 + argumentMutableValue=None): 1.9093 + self.doUnwrap = doUnwrap 1.9094 + CGProxySpecialOperation.__init__(self, descriptor, name, checkFound, 1.9095 + argumentMutableValue=argumentMutableValue) 1.9096 + 1.9097 + def define(self): 1.9098 + # Our first argument is the id we're getting. 1.9099 + argName = self.arguments[0].identifier.name 1.9100 + if argName == "index": 1.9101 + # We already have our index in a variable with that name 1.9102 + setIndex = "" 1.9103 + else: 1.9104 + setIndex = "uint32_t %s = index;\n" % argName 1.9105 + if self.doUnwrap: 1.9106 + unwrap = "%s* self = UnwrapProxy(proxy);\n" % self.descriptor.nativeType 1.9107 + else: 1.9108 + unwrap = "" 1.9109 + return (setIndex + unwrap + 1.9110 + CGProxySpecialOperation.define(self)) 1.9111 + 1.9112 + 1.9113 +class CGProxyIndexedGetter(CGProxyIndexedOperation): 1.9114 + """ 1.9115 + Class to generate a call to an indexed getter. If templateValues is not None 1.9116 + the returned value will be wrapped with wrapForType using templateValues. 1.9117 + 1.9118 + If doUnwrap is False, the caller is responsible for making sure a variable 1.9119 + named 'self' holds the C++ object somewhere where the code we generate 1.9120 + will see it. 1.9121 + 1.9122 + If checkFound is False, will just assert that the prop is found instead of 1.9123 + checking that it is before wrapping the value. 1.9124 + """ 1.9125 + def __init__(self, descriptor, templateValues=None, doUnwrap=True, 1.9126 + checkFound=True): 1.9127 + self.templateValues = templateValues 1.9128 + CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedGetter', 1.9129 + doUnwrap, checkFound) 1.9130 + 1.9131 + 1.9132 +class CGProxyIndexedPresenceChecker(CGProxyIndexedGetter): 1.9133 + """ 1.9134 + Class to generate a call that checks whether an indexed property exists. 1.9135 + 1.9136 + For now, we just delegate to CGProxyIndexedGetter 1.9137 + """ 1.9138 + def __init__(self, descriptor): 1.9139 + CGProxyIndexedGetter.__init__(self, descriptor) 1.9140 + self.cgRoot.append(CGGeneric("(void)result;\n")) 1.9141 + 1.9142 + 1.9143 +class CGProxyIndexedSetter(CGProxyIndexedOperation): 1.9144 + """ 1.9145 + Class to generate a call to an indexed setter. 1.9146 + """ 1.9147 + def __init__(self, descriptor, argumentMutableValue=None): 1.9148 + CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedSetter', 1.9149 + argumentMutableValue=argumentMutableValue) 1.9150 + 1.9151 + 1.9152 +class CGProxyIndexedDeleter(CGProxyIndexedOperation): 1.9153 + """ 1.9154 + Class to generate a call to an indexed deleter. 1.9155 + """ 1.9156 + def __init__(self, descriptor): 1.9157 + CGProxyIndexedOperation.__init__(self, descriptor, 'IndexedDeleter') 1.9158 + 1.9159 + 1.9160 +class CGProxyNamedOperation(CGProxySpecialOperation): 1.9161 + """ 1.9162 + Class to generate a call to a named operation. 1.9163 + 1.9164 + 'value' is the jsval to use for the name; None indicates that it should be 1.9165 + gotten from the property id. 1.9166 + """ 1.9167 + def __init__(self, descriptor, name, value=None, argumentMutableValue=None): 1.9168 + CGProxySpecialOperation.__init__(self, descriptor, name, 1.9169 + argumentMutableValue=argumentMutableValue) 1.9170 + self.value = value 1.9171 + 1.9172 + def define(self): 1.9173 + # Our first argument is the id we're getting. 1.9174 + argName = self.arguments[0].identifier.name 1.9175 + if argName == "id": 1.9176 + # deal with the name collision 1.9177 + idDecl = "JS::Rooted<jsid> id_(cx, id);\n" 1.9178 + idName = "id_" 1.9179 + else: 1.9180 + idDecl = "" 1.9181 + idName = "id" 1.9182 + unwrapString = fill( 1.9183 + """ 1.9184 + if (!ConvertJSValueToString(cx, nameVal, &nameVal, 1.9185 + eStringify, eStringify, ${argName})) { 1.9186 + return false; 1.9187 + } 1.9188 + """, 1.9189 + argName=argName) 1.9190 + if self.value is None: 1.9191 + # We're just using 'id', and if it's an atom we can take a 1.9192 + # fast path here. 1.9193 + unwrapString = fill( 1.9194 + """ 1.9195 + if (MOZ_LIKELY(JSID_IS_ATOM(${idName}))) { 1.9196 + ${argName}.SetData(js::GetAtomChars(JSID_TO_ATOM(${idName})), js::GetAtomLength(JSID_TO_ATOM(${idName}))); 1.9197 + } else { 1.9198 + nameVal = js::IdToValue(${idName}); 1.9199 + $*{unwrapString} 1.9200 + } 1.9201 + """, 1.9202 + idName=idName, 1.9203 + argName=argName, 1.9204 + unwrapString=unwrapString) 1.9205 + else: 1.9206 + unwrapString = ("nameVal = %s;\n" % self.value) + unwrapString 1.9207 + 1.9208 + # Sadly, we have to set up nameVal even if we have an atom id, 1.9209 + # because we don't know for sure, and we can end up needing it 1.9210 + # so it needs to be higher up the stack. Using a Maybe here 1.9211 + # seems like probable overkill. 1.9212 + return fill( 1.9213 + """ 1.9214 + JS::Rooted<JS::Value> nameVal(cx); 1.9215 + $*{idDecl} 1.9216 + binding_detail::FakeDependentString ${argName}; 1.9217 + $*{unwrapString} 1.9218 + 1.9219 + ${nativeType}* self = UnwrapProxy(proxy); 1.9220 + $*{op} 1.9221 + """, 1.9222 + idDecl=idDecl, 1.9223 + argName=argName, 1.9224 + unwrapString=unwrapString, 1.9225 + nativeType=self.descriptor.nativeType, 1.9226 + op=CGProxySpecialOperation.define(self)) 1.9227 + 1.9228 + 1.9229 +class CGProxyNamedGetter(CGProxyNamedOperation): 1.9230 + """ 1.9231 + Class to generate a call to an named getter. If templateValues is not None 1.9232 + the returned value will be wrapped with wrapForType using templateValues. 1.9233 + 'value' is the jsval to use for the name; None indicates that it should be 1.9234 + gotten from the property id. 1.9235 + """ 1.9236 + def __init__(self, descriptor, templateValues=None, value=None): 1.9237 + self.templateValues = templateValues 1.9238 + CGProxyNamedOperation.__init__(self, descriptor, 'NamedGetter', value) 1.9239 + 1.9240 + 1.9241 +class CGProxyNamedPresenceChecker(CGProxyNamedGetter): 1.9242 + """ 1.9243 + Class to generate a call that checks whether a named property exists. 1.9244 + 1.9245 + For now, we just delegate to CGProxyNamedGetter 1.9246 + """ 1.9247 + def __init__(self, descriptor): 1.9248 + CGProxyNamedGetter.__init__(self, descriptor) 1.9249 + self.cgRoot.append(CGGeneric("(void)result;\n")) 1.9250 + 1.9251 + 1.9252 +class CGProxyNamedSetter(CGProxyNamedOperation): 1.9253 + """ 1.9254 + Class to generate a call to a named setter. 1.9255 + """ 1.9256 + def __init__(self, descriptor, argumentMutableValue=None): 1.9257 + CGProxyNamedOperation.__init__(self, descriptor, 'NamedSetter', 1.9258 + argumentMutableValue=argumentMutableValue) 1.9259 + 1.9260 + 1.9261 +class CGProxyNamedDeleter(CGProxyNamedOperation): 1.9262 + """ 1.9263 + Class to generate a call to a named deleter. 1.9264 + """ 1.9265 + def __init__(self, descriptor): 1.9266 + CGProxyNamedOperation.__init__(self, descriptor, 'NamedDeleter') 1.9267 + 1.9268 + 1.9269 +class CGProxyIsProxy(CGAbstractMethod): 1.9270 + def __init__(self, descriptor): 1.9271 + args = [Argument('JSObject*', 'obj')] 1.9272 + CGAbstractMethod.__init__(self, descriptor, "IsProxy", "bool", args, alwaysInline=True) 1.9273 + 1.9274 + def declare(self): 1.9275 + return "" 1.9276 + 1.9277 + def definition_body(self): 1.9278 + return " return js::IsProxy(obj) && js::GetProxyHandler(obj) == DOMProxyHandler::getInstance();\n" 1.9279 + 1.9280 + 1.9281 +class CGProxyUnwrap(CGAbstractMethod): 1.9282 + def __init__(self, descriptor): 1.9283 + args = [Argument('JSObject*', 'obj')] 1.9284 + CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", descriptor.nativeType + '*', args, alwaysInline=True) 1.9285 + 1.9286 + def declare(self): 1.9287 + return "" 1.9288 + 1.9289 + def definition_body(self): 1.9290 + return indent(fill( 1.9291 + """ 1.9292 + MOZ_ASSERT(js::IsProxy(obj)); 1.9293 + if (js::GetProxyHandler(obj) != DOMProxyHandler::getInstance()) { 1.9294 + MOZ_ASSERT(xpc::WrapperFactory::IsXrayWrapper(obj)); 1.9295 + obj = js::UncheckedUnwrap(obj); 1.9296 + } 1.9297 + MOZ_ASSERT(IsProxy(obj)); 1.9298 + return static_cast<${type}*>(js::GetProxyPrivate(obj).toPrivate()); 1.9299 + """, 1.9300 + type=self.descriptor.nativeType)) 1.9301 + 1.9302 + 1.9303 +class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod): 1.9304 + def __init__(self, descriptor): 1.9305 + args = [Argument('JSContext*', 'cx'), 1.9306 + Argument('JS::Handle<JSObject*>', 'proxy'), 1.9307 + Argument('JS::Handle<jsid>', 'id'), 1.9308 + Argument('bool', 'ignoreNamedProps'), 1.9309 + Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc')] 1.9310 + ClassMethod.__init__(self, "getOwnPropDescriptor", "bool", args, 1.9311 + virtual=True, override=True) 1.9312 + self.descriptor = descriptor 1.9313 + 1.9314 + def getBody(self): 1.9315 + indexedGetter = self.descriptor.operations['IndexedGetter'] 1.9316 + indexedSetter = self.descriptor.operations['IndexedSetter'] 1.9317 + 1.9318 + if self.descriptor.supportsIndexedProperties(): 1.9319 + readonly = toStringBool(indexedSetter is None) 1.9320 + fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;\n" % readonly 1.9321 + templateValues = { 1.9322 + 'jsvalRef': 'desc.value()', 1.9323 + 'jsvalHandle': 'desc.value()', 1.9324 + 'obj': 'proxy', 1.9325 + 'successCode': fillDescriptor 1.9326 + } 1.9327 + getIndexed = fill( 1.9328 + """ 1.9329 + int32_t index = GetArrayIndexFromId(cx, id); 1.9330 + if (IsArrayIndex(index)) { 1.9331 + $*{callGetter} 1.9332 + } 1.9333 + 1.9334 + """, 1.9335 + callGetter=CGProxyIndexedGetter(self.descriptor, templateValues).define()) 1.9336 + else: 1.9337 + getIndexed = "" 1.9338 + 1.9339 + if UseHolderForUnforgeable(self.descriptor): 1.9340 + tryHolder = dedent(""" 1.9341 + if (!JS_GetPropertyDescriptorById(cx, ${holder}, id, desc)) { 1.9342 + return false; 1.9343 + } 1.9344 + MOZ_ASSERT_IF(desc.object(), desc.object() == ${holder}); 1.9345 + """) 1.9346 + 1.9347 + # We don't want to look at the unforgeable holder at all 1.9348 + # in the xray case; that part got handled already. 1.9349 + getUnforgeable = fill( 1.9350 + """ 1.9351 + if (!isXray) { 1.9352 + $*{callOnUnforgeable} 1.9353 + if (desc.object()) { 1.9354 + desc.object().set(proxy); 1.9355 + return true; 1.9356 + } 1.9357 + } 1.9358 + 1.9359 + """, 1.9360 + callOnUnforgeable=CallOnUnforgeableHolder(self.descriptor, tryHolder)) 1.9361 + else: 1.9362 + getUnforgeable = "" 1.9363 + 1.9364 + if self.descriptor.supportsNamedProperties(): 1.9365 + operations = self.descriptor.operations 1.9366 + readonly = toStringBool(operations['NamedSetter'] is None) 1.9367 + enumerable = ( 1.9368 + "self->NameIsEnumerable(Constify(%s))" % 1.9369 + # First [0] means first (and only) signature, [1] means 1.9370 + # "arguments" as opposed to return type, [0] means first (and 1.9371 + # only) argument. 1.9372 + operations['NamedGetter'].signatures()[0][1][0].identifier.name) 1.9373 + fillDescriptor = ( 1.9374 + "FillPropertyDescriptor(desc, proxy, %s, %s);\n" 1.9375 + "return true;\n" % (readonly, enumerable)) 1.9376 + templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()', 1.9377 + 'obj': 'proxy', 'successCode': fillDescriptor} 1.9378 + condition = "!HasPropertyOnPrototype(cx, proxy, id)" 1.9379 + if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'): 1.9380 + condition = "(!isXray || %s)" % condition 1.9381 + condition = "!ignoreNamedProps && " + condition 1.9382 + if self.descriptor.supportsIndexedProperties(): 1.9383 + condition = "!IsArrayIndex(index) && " + condition 1.9384 + namedGet = (CGIfWrapper(CGProxyNamedGetter(self.descriptor, templateValues), 1.9385 + condition).define() + 1.9386 + "\n") 1.9387 + else: 1.9388 + namedGet = "" 1.9389 + 1.9390 + return fill( 1.9391 + """ 1.9392 + bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy); 1.9393 + $*{getIndexed} 1.9394 + $*{getUnforgeable} 1.9395 + JS::Rooted<JSObject*> expando(cx); 1.9396 + if (!isXray && (expando = GetExpandoObject(proxy))) { 1.9397 + if (!JS_GetPropertyDescriptorById(cx, expando, id, desc)) { 1.9398 + return false; 1.9399 + } 1.9400 + if (desc.object()) { 1.9401 + // Pretend the property lives on the wrapper. 1.9402 + desc.object().set(proxy); 1.9403 + return true; 1.9404 + } 1.9405 + } 1.9406 + 1.9407 + $*{namedGet} 1.9408 + desc.object().set(nullptr); 1.9409 + return true; 1.9410 + """, 1.9411 + getIndexed=getIndexed, 1.9412 + getUnforgeable=getUnforgeable, 1.9413 + namedGet=namedGet) 1.9414 + 1.9415 + 1.9416 +class CGDOMJSProxyHandler_defineProperty(ClassMethod): 1.9417 + def __init__(self, descriptor): 1.9418 + args = [Argument('JSContext*', 'cx'), 1.9419 + Argument('JS::Handle<JSObject*>', 'proxy'), 1.9420 + Argument('JS::Handle<jsid>', 'id'), 1.9421 + Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'), 1.9422 + Argument('bool*', 'defined')] 1.9423 + ClassMethod.__init__(self, "defineProperty", "bool", args, virtual=True, override=True) 1.9424 + self.descriptor = descriptor 1.9425 + 1.9426 + def getBody(self): 1.9427 + set = "" 1.9428 + 1.9429 + indexedSetter = self.descriptor.operations['IndexedSetter'] 1.9430 + if indexedSetter: 1.9431 + if self.descriptor.operations['IndexedCreator'] is not indexedSetter: 1.9432 + raise TypeError("Can't handle creator that's different from the setter") 1.9433 + set += fill( 1.9434 + """ 1.9435 + int32_t index = GetArrayIndexFromId(cx, id); 1.9436 + if (IsArrayIndex(index)) { 1.9437 + *defined = true; 1.9438 + $*{callSetter} 1.9439 + return true; 1.9440 + } 1.9441 + """, 1.9442 + callSetter=CGProxyIndexedSetter(self.descriptor).define()) 1.9443 + elif self.descriptor.supportsIndexedProperties(): 1.9444 + set += fill( 1.9445 + """ 1.9446 + if (IsArrayIndex(GetArrayIndexFromId(cx, id))) { 1.9447 + return js::IsInNonStrictPropertySet(cx) || ThrowErrorMessage(cx, MSG_NO_INDEXED_SETTER, "${name}"); 1.9448 + } 1.9449 + """, 1.9450 + name=self.descriptor.name) 1.9451 + 1.9452 + if UseHolderForUnforgeable(self.descriptor): 1.9453 + defineOnUnforgeable = ("bool hasUnforgeable;\n" 1.9454 + "if (!JS_HasPropertyById(cx, ${holder}, id, &hasUnforgeable)) {\n" 1.9455 + " return false;\n" 1.9456 + "}\n" 1.9457 + "if (hasUnforgeable) {\n" 1.9458 + " *defined = true;" # SUPER BOGUS missing newline 1.9459 + " bool unused;\n" 1.9460 + " return js_DefineOwnProperty(cx, ${holder}, id, desc, &unused);\n" 1.9461 + "}\n" 1.9462 + "\n") # BOGUS extra blank line at end of block or method 1.9463 + set += CallOnUnforgeableHolder(self.descriptor, 1.9464 + defineOnUnforgeable, 1.9465 + "xpc::WrapperFactory::IsXrayWrapper(proxy)") 1.9466 + 1.9467 + namedSetter = self.descriptor.operations['NamedSetter'] 1.9468 + if namedSetter: 1.9469 + if self.descriptor.operations['NamedCreator'] is not namedSetter: 1.9470 + raise TypeError("Can't handle creator that's different from the setter") 1.9471 + # If we support indexed properties, we won't get down here for 1.9472 + # indices, so we can just do our setter unconditionally here. 1.9473 + set += fill( 1.9474 + """ 1.9475 + *defined = true; 1.9476 + $*{callSetter} 1.9477 + 1.9478 + return true; 1.9479 + 1.9480 + """, # BOGUS extra blank line at end of method 1.9481 + callSetter=CGProxyNamedSetter(self.descriptor).define()) 1.9482 + else: 1.9483 + if self.descriptor.supportsNamedProperties(): 1.9484 + set += fill( 1.9485 + """ 1.9486 + $*{presenceChecker} 1.9487 + 1.9488 + if (found) { 1.9489 + return js::IsInNonStrictPropertySet(cx) || ThrowErrorMessage(cx, MSG_NO_NAMED_SETTER, "${name}"); 1.9490 + } 1.9491 + """, 1.9492 + presenceChecker=CGProxyNamedPresenceChecker(self.descriptor).define(), 1.9493 + name=self.descriptor.name) 1.9494 + set += ("return mozilla::dom::DOMProxyHandler::defineProperty(%s);\n" % 1.9495 + ", ".join(a.name for a in self.args)) 1.9496 + return set 1.9497 + 1.9498 + 1.9499 +class CGDOMJSProxyHandler_delete(ClassMethod): 1.9500 + def __init__(self, descriptor): 1.9501 + args = [Argument('JSContext*', 'cx'), 1.9502 + Argument('JS::Handle<JSObject*>', 'proxy'), 1.9503 + Argument('JS::Handle<jsid>', 'id'), 1.9504 + Argument('bool*', 'bp')] 1.9505 + ClassMethod.__init__(self, "delete_", "bool", args, 1.9506 + virtual=True, override=True) 1.9507 + self.descriptor = descriptor 1.9508 + 1.9509 + def getBody(self): 1.9510 + def getDeleterBody(type): 1.9511 + """ 1.9512 + type should be "Named" or "Indexed" 1.9513 + """ 1.9514 + assert type in ("Named", "Indexed") 1.9515 + deleter = self.descriptor.operations[type + 'Deleter'] 1.9516 + if deleter: 1.9517 + if (not deleter.signatures()[0][0].isPrimitive() or 1.9518 + deleter.signatures()[0][0].nullable() or 1.9519 + deleter.signatures()[0][0].tag() != IDLType.Tags.bool): 1.9520 + setBp = "*bp = true;\n" 1.9521 + else: 1.9522 + setBp = dedent(""" 1.9523 + if (found) { 1.9524 + *bp = result; 1.9525 + } else { 1.9526 + *bp = true; 1.9527 + } 1.9528 + """) 1.9529 + body = (eval("CGProxy%sDeleter" % type)(self.descriptor).define() + 1.9530 + setBp) 1.9531 + elif eval("self.descriptor.supports%sProperties()" % type): 1.9532 + body = (eval("CGProxy%sPresenceChecker" % type)(self.descriptor).define() + 1.9533 + dedent(""" 1.9534 + if (found) { 1.9535 + *bp = false; 1.9536 + } else { 1.9537 + *bp = true; 1.9538 + } 1.9539 + """)) 1.9540 + else: 1.9541 + body = None 1.9542 + return body 1.9543 + 1.9544 + delete = dedent(""" 1.9545 + MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy), 1.9546 + "Should not have a XrayWrapper here"); 1.9547 + 1.9548 + """) 1.9549 + 1.9550 + indexedBody = getDeleterBody("Indexed") 1.9551 + if indexedBody is not None: 1.9552 + delete += fill( 1.9553 + """ 1.9554 + int32_t index = GetArrayIndexFromId(cx, id); 1.9555 + if (IsArrayIndex(index)) { 1.9556 + $*{indexedBody} 1.9557 + // We always return here, even if the property was not found 1.9558 + return true; 1.9559 + } 1.9560 + """, 1.9561 + indexedBody=indexedBody) 1.9562 + 1.9563 + if UseHolderForUnforgeable(self.descriptor): 1.9564 + unforgeable = dedent(""" 1.9565 + bool hasUnforgeable; 1.9566 + if (!JS_HasPropertyById(cx, ${holder}, id, &hasUnforgeable)) { 1.9567 + return false; 1.9568 + } 1.9569 + if (hasUnforgeable) { 1.9570 + *bp = false; 1.9571 + return true; 1.9572 + } 1.9573 + """) 1.9574 + delete += CallOnUnforgeableHolder(self.descriptor, unforgeable) 1.9575 + delete += "\n" 1.9576 + 1.9577 + namedBody = getDeleterBody("Named") 1.9578 + if namedBody is not None: 1.9579 + # We always return above for an index id in the case when we support 1.9580 + # indexed properties, so we can just treat the id as a name 1.9581 + # unconditionally here. 1.9582 + delete += (namedBody + 1.9583 + "if (found) {\n" 1.9584 + " return true;\n" 1.9585 + "}\n\n") # BOGUS extra blank line 1.9586 + if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'): 1.9587 + delete = CGIfWrapper(CGGeneric(delete), 1.9588 + "!HasPropertyOnPrototype(cx, proxy, id)").define() 1.9589 + else: 1.9590 + delete += "\n" # BOGUS extra blank line 1.9591 + 1.9592 + delete += dedent(""" 1.9593 + 1.9594 + return dom::DOMProxyHandler::delete_(cx, proxy, id, bp); 1.9595 + """) 1.9596 + 1.9597 + return delete 1.9598 + 1.9599 + 1.9600 +class CGDOMJSProxyHandler_ownPropNames(ClassMethod): 1.9601 + def __init__(self, descriptor, ): 1.9602 + args = [Argument('JSContext*', 'cx'), 1.9603 + Argument('JS::Handle<JSObject*>', 'proxy'), 1.9604 + Argument('unsigned', 'flags'), 1.9605 + Argument('JS::AutoIdVector&', 'props')] 1.9606 + ClassMethod.__init__(self, "ownPropNames", "bool", args, 1.9607 + virtual=True, override=True) 1.9608 + self.descriptor = descriptor 1.9609 + 1.9610 + def getBody(self): 1.9611 + # Per spec, we do indices, then named props, then everything else 1.9612 + if self.descriptor.supportsIndexedProperties(): 1.9613 + addIndices = dedent(""" 1.9614 + 1.9615 + uint32_t length = UnwrapProxy(proxy)->Length(); 1.9616 + MOZ_ASSERT(int32_t(length) >= 0); 1.9617 + for (int32_t i = 0; i < int32_t(length); ++i) { 1.9618 + if (!props.append(INT_TO_JSID(i))) { 1.9619 + return false; 1.9620 + } 1.9621 + } 1.9622 + """) 1.9623 + else: 1.9624 + addIndices = "" 1.9625 + 1.9626 + if UseHolderForUnforgeable(self.descriptor): 1.9627 + addUnforgeable = dedent(""" 1.9628 + if (!js::GetPropertyNames(cx, ${holder}, flags, &props)) { 1.9629 + return false; 1.9630 + } 1.9631 + """) 1.9632 + addUnforgeable = CallOnUnforgeableHolder(self.descriptor, 1.9633 + addUnforgeable, 1.9634 + "isXray") 1.9635 + else: 1.9636 + addUnforgeable = "" 1.9637 + 1.9638 + if self.descriptor.supportsNamedProperties(): 1.9639 + if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'): 1.9640 + shadow = "!isXray" 1.9641 + else: 1.9642 + shadow = "false" 1.9643 + addNames = fill( 1.9644 + """ 1.9645 + 1.9646 + nsTArray<nsString> names; 1.9647 + UnwrapProxy(proxy)->GetSupportedNames(flags, names); 1.9648 + if (!AppendNamedPropertyIds(cx, proxy, names, ${shadow}, props)) { 1.9649 + return false; 1.9650 + } 1.9651 + """, 1.9652 + shadow=shadow) 1.9653 + else: 1.9654 + addNames = "" 1.9655 + 1.9656 + return fill( 1.9657 + """ 1.9658 + bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy); 1.9659 + $*{addIndices} 1.9660 + $*{addUnforgeable} 1.9661 + $*{addNames} 1.9662 + 1.9663 + JS::Rooted<JSObject*> expando(cx); 1.9664 + if (!isXray && (expando = DOMProxyHandler::GetExpandoObject(proxy)) && 1.9665 + !js::GetPropertyNames(cx, expando, flags, &props)) { 1.9666 + return false; 1.9667 + } 1.9668 + 1.9669 + return true; 1.9670 + """, 1.9671 + addIndices=addIndices, 1.9672 + addUnforgeable=addUnforgeable, 1.9673 + addNames=addNames) 1.9674 + 1.9675 + 1.9676 +class CGDOMJSProxyHandler_hasOwn(ClassMethod): 1.9677 + def __init__(self, descriptor): 1.9678 + args = [Argument('JSContext*', 'cx'), 1.9679 + Argument('JS::Handle<JSObject*>', 'proxy'), 1.9680 + Argument('JS::Handle<jsid>', 'id'), 1.9681 + Argument('bool*', 'bp')] 1.9682 + ClassMethod.__init__(self, "hasOwn", "bool", args, 1.9683 + virtual=True, override=True) 1.9684 + self.descriptor = descriptor 1.9685 + 1.9686 + def getBody(self): 1.9687 + if self.descriptor.supportsIndexedProperties(): 1.9688 + indexed = fill( 1.9689 + """ 1.9690 + int32_t index = GetArrayIndexFromId(cx, id); 1.9691 + if (IsArrayIndex(index)) { 1.9692 + $*{presenceChecker} 1.9693 + 1.9694 + *bp = found; 1.9695 + return true; 1.9696 + } 1.9697 + 1.9698 + """, 1.9699 + presenceChecker=CGProxyIndexedPresenceChecker(self.descriptor).define()) 1.9700 + else: 1.9701 + indexed = "" 1.9702 + 1.9703 + if UseHolderForUnforgeable(self.descriptor): 1.9704 + unforgeable = dedent(""" 1.9705 + bool b = true; 1.9706 + bool ok = JS_AlreadyHasOwnPropertyById(cx, ${holder}, id, &b); 1.9707 + *bp = !!b; 1.9708 + if (!ok || *bp) { 1.9709 + return ok; 1.9710 + } 1.9711 + """) 1.9712 + unforgeable = CallOnUnforgeableHolder(self.descriptor, unforgeable) 1.9713 + else: 1.9714 + unforgeable = "" 1.9715 + 1.9716 + if self.descriptor.supportsNamedProperties(): 1.9717 + # If we support indexed properties we always return above for index 1.9718 + # property names, so no need to check for those here. 1.9719 + named = (CGProxyNamedPresenceChecker(self.descriptor).define() + 1.9720 + "\n" + 1.9721 + "*bp = found;\n") 1.9722 + if not self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'): 1.9723 + # BOGUS extra blank line at end of block 1.9724 + named = CGIfWrapper(CGGeneric(named + "return true;\n\n"), 1.9725 + "!HasPropertyOnPrototype(cx, proxy, id)").define() 1.9726 + named += "*bp = false;\n" 1.9727 + else: 1.9728 + named += "\n" 1.9729 + else: 1.9730 + named = "*bp = false;\n" 1.9731 + 1.9732 + return fill( 1.9733 + """ 1.9734 + MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy), 1.9735 + "Should not have a XrayWrapper here"); 1.9736 + 1.9737 + $*{indexed} 1.9738 + $*{unforgeable} 1.9739 + 1.9740 + JS::Rooted<JSObject*> expando(cx, GetExpandoObject(proxy)); 1.9741 + if (expando) { 1.9742 + bool b = true; 1.9743 + bool ok = JS_HasPropertyById(cx, expando, id, &b); 1.9744 + *bp = !!b; 1.9745 + if (!ok || *bp) { 1.9746 + return ok; 1.9747 + } 1.9748 + } 1.9749 + 1.9750 + $*{named} 1.9751 + return true; 1.9752 + """, 1.9753 + indexed=indexed, 1.9754 + unforgeable=unforgeable, 1.9755 + named=named) 1.9756 + 1.9757 + 1.9758 +class CGDOMJSProxyHandler_get(ClassMethod): 1.9759 + def __init__(self, descriptor): 1.9760 + args = [Argument('JSContext*', 'cx'), 1.9761 + Argument('JS::Handle<JSObject*>', 'proxy'), 1.9762 + Argument('JS::Handle<JSObject*>', 'receiver'), 1.9763 + Argument('JS::Handle<jsid>', 'id'), 1.9764 + Argument('JS::MutableHandle<JS::Value>', 'vp')] 1.9765 + ClassMethod.__init__(self, "get", "bool", args, 1.9766 + virtual=True, override=True) 1.9767 + self.descriptor = descriptor 1.9768 + 1.9769 + def getBody(self): 1.9770 + getUnforgeableOrExpando = "JS::Rooted<JSObject*> sharedRoot(cx);\n" 1.9771 + if UseHolderForUnforgeable(self.descriptor): 1.9772 + hasUnforgeable = dedent(""" 1.9773 + bool hasUnforgeable; 1.9774 + if (!JS_AlreadyHasOwnPropertyById(cx, ${holder}, id, &hasUnforgeable)) { 1.9775 + return false; 1.9776 + } 1.9777 + if (hasUnforgeable) { 1.9778 + return JS_ForwardGetPropertyTo(cx, ${holder}, id, proxy, vp); 1.9779 + } 1.9780 + """) 1.9781 + getUnforgeableOrExpando += CallOnUnforgeableHolder(self.descriptor, 1.9782 + hasUnforgeable, 1.9783 + useSharedRoot=True) 1.9784 + getUnforgeableOrExpando += dedent(""" 1.9785 + { // Scope for expando 1.9786 + JS::Rooted<JSObject*>& expando(sharedRoot); 1.9787 + expando = DOMProxyHandler::GetExpandoObject(proxy); 1.9788 + if (expando) { 1.9789 + bool hasProp; 1.9790 + if (!JS_HasPropertyById(cx, expando, id, &hasProp)) { 1.9791 + return false; 1.9792 + } 1.9793 + 1.9794 + if (hasProp) { 1.9795 + // Forward the get to the expando object, but our receiver is whatever our 1.9796 + // receiver is. 1.9797 + return JS_ForwardGetPropertyTo(cx, expando, id, receiver, vp); 1.9798 + } 1.9799 + } 1.9800 + } 1.9801 + """) 1.9802 + 1.9803 + templateValues = {'jsvalRef': 'vp', 'jsvalHandle': 'vp', 'obj': 'proxy'} 1.9804 + 1.9805 + if self.descriptor.supportsIndexedProperties(): 1.9806 + getIndexedOrExpando = fill( 1.9807 + """ 1.9808 + int32_t index = GetArrayIndexFromId(cx, id); 1.9809 + if (IsArrayIndex(index)) { 1.9810 + $*{callGetter} 1.9811 + // Even if we don't have this index, we don't forward the 1.9812 + // get on to our expando object. 1.9813 + } else { 1.9814 + $*{getUnforgeableOrExpando} 1.9815 + } 1.9816 + """, 1.9817 + callGetter=CGProxyIndexedGetter(self.descriptor, templateValues).define(), 1.9818 + getUnforgeableOrExpando=getUnforgeableOrExpando) 1.9819 + else: 1.9820 + getIndexedOrExpando = getUnforgeableOrExpando 1.9821 + 1.9822 + if self.descriptor.supportsNamedProperties(): 1.9823 + getNamed = CGProxyNamedGetter(self.descriptor, templateValues) 1.9824 + if self.descriptor.supportsIndexedProperties(): 1.9825 + getNamed = CGIfWrapper(getNamed, "!IsArrayIndex(index)") 1.9826 + getNamed = getNamed.define() + "\n" 1.9827 + else: 1.9828 + getNamed = "" 1.9829 + 1.9830 + getOnPrototype = dedent(""" 1.9831 + bool foundOnPrototype; 1.9832 + if (!GetPropertyOnPrototype(cx, proxy, id, &foundOnPrototype, vp.address())) { 1.9833 + return false; 1.9834 + } 1.9835 + 1.9836 + if (foundOnPrototype) { 1.9837 + return true; 1.9838 + } 1.9839 + 1.9840 + """) 1.9841 + if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'): 1.9842 + getNamed = getNamed + getOnPrototype 1.9843 + else: 1.9844 + getNamed = getOnPrototype + getNamed 1.9845 + 1.9846 + return fill( 1.9847 + """ 1.9848 + MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy), 1.9849 + "Should not have a XrayWrapper here"); 1.9850 + 1.9851 + $*{indexedOrExpando} 1.9852 + 1.9853 + $*{named} 1.9854 + vp.setUndefined(); 1.9855 + return true; 1.9856 + """, 1.9857 + indexedOrExpando=getIndexedOrExpando, 1.9858 + named=getNamed) 1.9859 + 1.9860 + 1.9861 +class CGDOMJSProxyHandler_setCustom(ClassMethod): 1.9862 + def __init__(self, descriptor): 1.9863 + args = [Argument('JSContext*', 'cx'), 1.9864 + Argument('JS::Handle<JSObject*>', 'proxy'), 1.9865 + Argument('JS::Handle<jsid>', 'id'), 1.9866 + Argument('JS::MutableHandle<JS::Value>', 'vp'), 1.9867 + Argument('bool*', 'done')] 1.9868 + ClassMethod.__init__(self, "setCustom", "bool", args, virtual=True, override=True) 1.9869 + self.descriptor = descriptor 1.9870 + 1.9871 + def getBody(self): 1.9872 + assertion = ("MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),\n" 1.9873 + ' "Should not have a XrayWrapper here");\n') 1.9874 + 1.9875 + # Correctness first. If we have a NamedSetter and [OverrideBuiltins], 1.9876 + # always call the NamedSetter and never do anything else. 1.9877 + namedSetter = self.descriptor.operations['NamedSetter'] 1.9878 + if (namedSetter is not None and 1.9879 + self.descriptor.interface.getExtendedAttribute('OverrideBuiltins')): 1.9880 + # Check assumptions. 1.9881 + if self.descriptor.supportsIndexedProperties(): 1.9882 + raise ValueError("In interface " + self.descriptor.name + ": " + 1.9883 + "Can't cope with [OverrideBuiltins] and an indexed getter") 1.9884 + if self.descriptor.operations['NamedCreator'] is not namedSetter: 1.9885 + raise ValueError("In interface " + self.descriptor.name + ": " + 1.9886 + "Can't cope with named setter that is not also a named creator") 1.9887 + if UseHolderForUnforgeable(self.descriptor): 1.9888 + raise ValueError("In interface " + self.descriptor.name + ": " + 1.9889 + "Can't cope with [OverrideBuiltins] and unforgeable members") 1.9890 + 1.9891 + callSetter = CGProxyNamedSetter(self.descriptor, argumentMutableValue="vp") 1.9892 + return (assertion + 1.9893 + callSetter.define() + 1.9894 + "*done = true;\n" 1.9895 + "return true;\n") 1.9896 + 1.9897 + # As an optimization, if we are going to call an IndexedSetter, go 1.9898 + # ahead and call it and have done. 1.9899 + indexedSetter = self.descriptor.operations['IndexedSetter'] 1.9900 + if indexedSetter is not None: 1.9901 + if self.descriptor.operations['IndexedCreator'] is not indexedSetter: 1.9902 + raise ValueError("In interface " + self.descriptor.name + ": " + 1.9903 + "Can't cope with indexed setter that is not " + 1.9904 + "also an indexed creator") 1.9905 + setIndexed = fill( 1.9906 + """ 1.9907 + int32_t index = GetArrayIndexFromId(cx, id); 1.9908 + if (IsArrayIndex(index)) { 1.9909 + $*{callSetter} 1.9910 + *done = true; 1.9911 + return true; 1.9912 + } 1.9913 + 1.9914 + """, 1.9915 + callSetter=CGProxyIndexedSetter(self.descriptor, 1.9916 + argumentMutableValue="vp").define()) 1.9917 + else: 1.9918 + setIndexed = "" 1.9919 + 1.9920 + return (assertion + 1.9921 + setIndexed + 1.9922 + "*done = false;\n" 1.9923 + "return true;\n") 1.9924 + 1.9925 + 1.9926 +class CGDOMJSProxyHandler_className(ClassMethod): 1.9927 + def __init__(self, descriptor): 1.9928 + args = [Argument('JSContext*', 'cx'), 1.9929 + Argument('JS::Handle<JSObject*>', 'proxy')] 1.9930 + ClassMethod.__init__(self, "className", "const char*", args, 1.9931 + virtual=True, override=True) 1.9932 + self.descriptor = descriptor 1.9933 + 1.9934 + def getBody(self): 1.9935 + return 'return "%s";\n' % self.descriptor.name 1.9936 + 1.9937 + 1.9938 +class CGDOMJSProxyHandler_finalizeInBackground(ClassMethod): 1.9939 + def __init__(self, descriptor): 1.9940 + args = [Argument('JS::Value', 'priv')] 1.9941 + ClassMethod.__init__(self, "finalizeInBackground", "bool", args, 1.9942 + virtual=True, override=True) 1.9943 + self.descriptor = descriptor 1.9944 + 1.9945 + def getBody(self): 1.9946 + return "return false;\n" 1.9947 + 1.9948 + 1.9949 +class CGDOMJSProxyHandler_finalize(ClassMethod): 1.9950 + def __init__(self, descriptor): 1.9951 + args = [Argument('JSFreeOp*', 'fop'), Argument('JSObject*', 'proxy')] 1.9952 + ClassMethod.__init__(self, "finalize", "void", args, 1.9953 + virtual=True, override=True) 1.9954 + self.descriptor = descriptor 1.9955 + 1.9956 + def getBody(self): 1.9957 + return ("%s* self = UnwrapProxy(proxy);\n\n" % self.descriptor.nativeType + 1.9958 + finalizeHook(self.descriptor, FINALIZE_HOOK_NAME, self.args[0].name).define()) 1.9959 + 1.9960 + 1.9961 +class CGDOMJSProxyHandler_slice(ClassMethod): 1.9962 + def __init__(self, descriptor): 1.9963 + assert descriptor.supportsIndexedProperties() 1.9964 + 1.9965 + args = [Argument('JSContext*', 'cx'), 1.9966 + Argument('JS::Handle<JSObject*>', 'proxy'), 1.9967 + Argument('uint32_t', 'begin'), 1.9968 + Argument('uint32_t', 'end'), 1.9969 + Argument('JS::Handle<JSObject*>', 'array')] 1.9970 + ClassMethod.__init__(self, "slice", "bool", args, virtual=True, override=True) 1.9971 + self.descriptor = descriptor 1.9972 + 1.9973 + def getBody(self): 1.9974 + # Just like getOwnPropertyNames we'll assume that we have no holes, so 1.9975 + # we have all properties from 0 to length. If that ever changes 1.9976 + # (unlikely), we'll need to do something a bit more clever with how we 1.9977 + # forward on to our ancestor. 1.9978 + 1.9979 + templateValues = { 1.9980 + 'jsvalRef': 'temp', 1.9981 + 'jsvalHandle': '&temp', 1.9982 + 'obj': 'proxy', 1.9983 + 'successCode': ("js::UnsafeDefineElement(cx, array, index - begin, temp);\n" 1.9984 + "continue;\n") 1.9985 + } 1.9986 + get = CGProxyIndexedGetter(self.descriptor, templateValues, False, False).define() 1.9987 + 1.9988 + return fill( 1.9989 + """ 1.9990 + JS::Rooted<JS::Value> temp(cx); 1.9991 + MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy), 1.9992 + "Should not have a XrayWrapper here"); 1.9993 + 1.9994 + ${nativeType}* self = UnwrapProxy(proxy); 1.9995 + uint32_t length = self->Length(); 1.9996 + // Compute the end of the indices we'll get ourselves 1.9997 + uint32_t ourEnd = std::max(begin, std::min(end, length)); 1.9998 + 1.9999 + for (uint32_t index = begin; index < ourEnd; ++index) { 1.10000 + $*{get} 1.10001 + } 1.10002 + 1.10003 + if (end > ourEnd) { 1.10004 + JS::Rooted<JSObject*> proto(cx); 1.10005 + if (!js::GetObjectProto(cx, proxy, &proto)) { 1.10006 + return false; 1.10007 + } 1.10008 + return js::SliceSlowly(cx, proto, proxy, ourEnd, end, array); 1.10009 + } 1.10010 + 1.10011 + return true; 1.10012 + """, 1.10013 + nativeType=self.descriptor.nativeType, 1.10014 + get=get) 1.10015 + 1.10016 + 1.10017 +class CGDOMJSProxyHandler_getInstance(ClassMethod): 1.10018 + def __init__(self): 1.10019 + ClassMethod.__init__(self, "getInstance", "DOMProxyHandler*", [], static=True) 1.10020 + 1.10021 + def getBody(self): 1.10022 + return dedent(""" 1.10023 + static DOMProxyHandler instance; 1.10024 + return &instance; 1.10025 + """) 1.10026 + 1.10027 + 1.10028 +class CGDOMJSProxyHandler(CGClass): 1.10029 + def __init__(self, descriptor): 1.10030 + assert (descriptor.supportsIndexedProperties() or 1.10031 + descriptor.supportsNamedProperties()) 1.10032 + methods = [CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor), 1.10033 + CGDOMJSProxyHandler_defineProperty(descriptor), 1.10034 + ClassUsingDeclaration("mozilla::dom::DOMProxyHandler", 1.10035 + "defineProperty"), 1.10036 + CGDOMJSProxyHandler_ownPropNames(descriptor), 1.10037 + CGDOMJSProxyHandler_hasOwn(descriptor), 1.10038 + CGDOMJSProxyHandler_get(descriptor), 1.10039 + CGDOMJSProxyHandler_className(descriptor), 1.10040 + CGDOMJSProxyHandler_finalizeInBackground(descriptor), 1.10041 + CGDOMJSProxyHandler_finalize(descriptor), 1.10042 + CGDOMJSProxyHandler_getInstance(), 1.10043 + CGDOMJSProxyHandler_delete(descriptor)] 1.10044 + if descriptor.supportsIndexedProperties(): 1.10045 + methods.append(CGDOMJSProxyHandler_slice(descriptor)) 1.10046 + if (descriptor.operations['IndexedSetter'] is not None or 1.10047 + (descriptor.operations['NamedSetter'] is not None and 1.10048 + descriptor.interface.getExtendedAttribute('OverrideBuiltins'))): 1.10049 + methods.append(CGDOMJSProxyHandler_setCustom(descriptor)) 1.10050 + 1.10051 + CGClass.__init__(self, 'DOMProxyHandler', 1.10052 + bases=[ClassBase('mozilla::dom::DOMProxyHandler')], 1.10053 + methods=methods) 1.10054 + 1.10055 + 1.10056 +class CGDOMJSProxyHandlerDeclarer(CGThing): 1.10057 + """ 1.10058 + A class for declaring a DOMProxyHandler. 1.10059 + """ 1.10060 + def __init__(self, handlerThing): 1.10061 + self.handlerThing = handlerThing 1.10062 + 1.10063 + def declare(self): 1.10064 + # Our class declaration should happen when we're defining 1.10065 + return "" 1.10066 + 1.10067 + def define(self): 1.10068 + return self.handlerThing.declare() 1.10069 + 1.10070 + 1.10071 +class CGDOMJSProxyHandlerDefiner(CGThing): 1.10072 + """ 1.10073 + A class for defining a DOMProxyHandler. 1.10074 + """ 1.10075 + def __init__(self, handlerThing): 1.10076 + self.handlerThing = handlerThing 1.10077 + 1.10078 + def declare(self): 1.10079 + return "" 1.10080 + 1.10081 + def define(self): 1.10082 + return self.handlerThing.define() 1.10083 + 1.10084 + 1.10085 +def stripTrailingWhitespace(text): 1.10086 + tail = '\n' if text.endswith('\n') else '' 1.10087 + lines = text.splitlines() 1.10088 + return '\n'.join(line.rstrip() for line in lines) + tail 1.10089 + 1.10090 + 1.10091 +class CGDescriptor(CGThing): 1.10092 + def __init__(self, descriptor): 1.10093 + CGThing.__init__(self) 1.10094 + 1.10095 + assert not descriptor.concrete or descriptor.interface.hasInterfacePrototypeObject() 1.10096 + 1.10097 + if descriptor.nativeOwnership == 'owned' and ( 1.10098 + descriptor.interface.hasChildInterfaces() or 1.10099 + descriptor.interface.parent): 1.10100 + raise TypeError("Owned interface cannot have a parent or children") 1.10101 + 1.10102 + self._deps = descriptor.interface.getDeps() 1.10103 + 1.10104 + cgThings = [] 1.10105 + cgThings.append(CGGeneric(declare="typedef %s NativeType;\n" % 1.10106 + descriptor.nativeType)) 1.10107 + # These are set to true if at least one non-static 1.10108 + # method/getter/setter or jsonifier exist on the interface. 1.10109 + (hasMethod, hasGetter, hasLenientGetter, hasSetter, hasJsonifier, 1.10110 + hasLenientSetter) = False, False, False, False, False, False 1.10111 + crossOriginMethods, crossOriginGetters, crossOriginSetters = set(), set(), set() 1.10112 + for n in descriptor.interface.namedConstructors: 1.10113 + cgThings.append(CGClassConstructor(descriptor, n, 1.10114 + NamedConstructorName(n))) 1.10115 + for m in descriptor.interface.members: 1.10116 + if m.isMethod() and m.identifier.name == 'queryInterface': 1.10117 + continue 1.10118 + if m.isMethod() and m == descriptor.operations['Jsonifier']: 1.10119 + hasJsonifier = True 1.10120 + hasMethod = descriptor.needsSpecialGenericOps() 1.10121 + jsonifierMethod = m 1.10122 + elif (m.isMethod() and 1.10123 + (not m.isIdentifierLess() or m == descriptor.operations['Stringifier'])): 1.10124 + if m.isStatic(): 1.10125 + assert descriptor.interface.hasInterfaceObject 1.10126 + cgThings.append(CGStaticMethod(descriptor, m)) 1.10127 + if m.returnsPromise(): 1.10128 + cgThings.append(CGStaticMethodJitinfo(m)) 1.10129 + elif descriptor.interface.hasInterfacePrototypeObject(): 1.10130 + specializedMethod = CGSpecializedMethod(descriptor, m) 1.10131 + cgThings.append(specializedMethod) 1.10132 + if m.returnsPromise(): 1.10133 + cgThings.append(CGMethodPromiseWrapper(descriptor, specializedMethod)) 1.10134 + cgThings.append(CGMemberJITInfo(descriptor, m)) 1.10135 + if m.getExtendedAttribute("CrossOriginCallable"): 1.10136 + crossOriginMethods.add(m.identifier.name) 1.10137 + elif descriptor.needsSpecialGenericOps(): 1.10138 + hasMethod = True 1.10139 + elif m.isAttr(): 1.10140 + if m.stringifier: 1.10141 + raise TypeError("Stringifier attributes not supported yet. " 1.10142 + "See bug 824857.\n" 1.10143 + "%s" % m.location) 1.10144 + if m.isStatic(): 1.10145 + assert descriptor.interface.hasInterfaceObject 1.10146 + cgThings.append(CGStaticGetter(descriptor, m)) 1.10147 + elif descriptor.interface.hasInterfacePrototypeObject(): 1.10148 + cgThings.append(CGSpecializedGetter(descriptor, m)) 1.10149 + if m.hasLenientThis(): 1.10150 + hasLenientGetter = True 1.10151 + elif m.getExtendedAttribute("CrossOriginReadable"): 1.10152 + crossOriginGetters.add(m.identifier.name) 1.10153 + elif descriptor.needsSpecialGenericOps(): 1.10154 + hasGetter = True 1.10155 + if not m.readonly: 1.10156 + for extAttr in ["PutForwards", "Replaceable"]: 1.10157 + if m.getExtendedAttribute(extAttr): 1.10158 + raise TypeError("Writable attributes should not " 1.10159 + "have %s specified.\n" 1.10160 + "%s" % 1.10161 + (extAttr, m.location)) 1.10162 + if m.isStatic(): 1.10163 + assert descriptor.interface.hasInterfaceObject 1.10164 + cgThings.append(CGStaticSetter(descriptor, m)) 1.10165 + elif descriptor.interface.hasInterfacePrototypeObject(): 1.10166 + cgThings.append(CGSpecializedSetter(descriptor, m)) 1.10167 + if m.hasLenientThis(): 1.10168 + hasLenientSetter = True 1.10169 + elif m.getExtendedAttribute("CrossOriginWritable"): 1.10170 + crossOriginSetters.add(m.identifier.name) 1.10171 + elif descriptor.needsSpecialGenericOps(): 1.10172 + hasSetter = True 1.10173 + elif m.getExtendedAttribute("PutForwards"): 1.10174 + cgThings.append(CGSpecializedForwardingSetter(descriptor, m)) 1.10175 + if m.getExtendedAttribute("CrossOriginWritable"): 1.10176 + crossOriginSetters.add(m.identifier.name) 1.10177 + elif descriptor.needsSpecialGenericOps(): 1.10178 + hasSetter = True 1.10179 + elif m.getExtendedAttribute("Replaceable"): 1.10180 + cgThings.append(CGSpecializedReplaceableSetter(descriptor, m)) 1.10181 + if descriptor.needsSpecialGenericOps(): 1.10182 + hasSetter = True 1.10183 + if (not m.isStatic() and 1.10184 + descriptor.interface.hasInterfacePrototypeObject()): 1.10185 + cgThings.append(CGMemberJITInfo(descriptor, m)) 1.10186 + if hasJsonifier: 1.10187 + cgThings.append(CGJsonifierMethod(descriptor, jsonifierMethod)) 1.10188 + cgThings.append(CGMemberJITInfo(descriptor, jsonifierMethod)) 1.10189 + if hasMethod: 1.10190 + cgThings.append(CGGenericMethod(descriptor)) 1.10191 + if len(crossOriginMethods): 1.10192 + cgThings.append(CGGenericMethod(descriptor, 1.10193 + allowCrossOriginThis=True)) 1.10194 + if hasGetter: 1.10195 + cgThings.append(CGGenericGetter(descriptor)) 1.10196 + if hasLenientGetter: 1.10197 + cgThings.append(CGGenericGetter(descriptor, lenientThis=True)) 1.10198 + if len(crossOriginGetters): 1.10199 + cgThings.append(CGGenericGetter(descriptor, 1.10200 + allowCrossOriginThis=True)) 1.10201 + if hasSetter: 1.10202 + cgThings.append(CGGenericSetter(descriptor)) 1.10203 + if hasLenientSetter: 1.10204 + cgThings.append(CGGenericSetter(descriptor, lenientThis=True)) 1.10205 + if len(crossOriginSetters): 1.10206 + cgThings.append(CGGenericSetter(descriptor, 1.10207 + allowCrossOriginThis=True)) 1.10208 + 1.10209 + if descriptor.interface.getNavigatorProperty(): 1.10210 + cgThings.append(CGConstructNavigatorObjectHelper(descriptor)) 1.10211 + cgThings.append(CGConstructNavigatorObject(descriptor)) 1.10212 + 1.10213 + if descriptor.concrete and not descriptor.proxy: 1.10214 + if wantsAddProperty(descriptor): 1.10215 + cgThings.append(CGAddPropertyHook(descriptor)) 1.10216 + 1.10217 + # Always have a finalize hook, regardless of whether the class 1.10218 + # wants a custom hook. 1.10219 + cgThings.append(CGClassFinalizeHook(descriptor)) 1.10220 + 1.10221 + properties = PropertyArrays(descriptor) 1.10222 + cgThings.append(CGGeneric(define=str(properties))) 1.10223 + cgThings.append(CGNativeProperties(descriptor, properties)) 1.10224 + 1.10225 + # Set up our Xray callbacks as needed. Note that we don't need to do 1.10226 + # it in workers. 1.10227 + if not descriptor.workers and descriptor.concrete and descriptor.proxy: 1.10228 + cgThings.append(CGResolveOwnProperty(descriptor)) 1.10229 + cgThings.append(CGEnumerateOwnProperties(descriptor)) 1.10230 + elif descriptor.needsXrayResolveHooks(): 1.10231 + cgThings.append(CGResolveOwnPropertyViaNewresolve(descriptor)) 1.10232 + cgThings.append(CGEnumerateOwnPropertiesViaGetOwnPropertyNames(descriptor)) 1.10233 + 1.10234 + # Now that we have our ResolveOwnProperty/EnumerateOwnProperties stuff 1.10235 + # done, set up our NativePropertyHooks. 1.10236 + cgThings.append(CGNativePropertyHooks(descriptor, properties)) 1.10237 + 1.10238 + if descriptor.interface.hasInterfaceObject(): 1.10239 + cgThings.append(CGClassConstructor(descriptor, 1.10240 + descriptor.interface.ctor())) 1.10241 + cgThings.append(CGClassHasInstanceHook(descriptor)) 1.10242 + cgThings.append(CGInterfaceObjectJSClass(descriptor, properties)) 1.10243 + if descriptor.needsConstructHookHolder(): 1.10244 + cgThings.append(CGClassConstructHookHolder(descriptor)) 1.10245 + cgThings.append(CGNamedConstructors(descriptor)) 1.10246 + 1.10247 + cgThings.append(CGLegacyCallHook(descriptor)) 1.10248 + if descriptor.interface.getExtendedAttribute("NeedNewResolve"): 1.10249 + cgThings.append(CGNewResolveHook(descriptor)) 1.10250 + cgThings.append(CGEnumerateHook(descriptor)) 1.10251 + 1.10252 + if descriptor.interface.hasInterfacePrototypeObject(): 1.10253 + cgThings.append(CGPrototypeJSClass(descriptor, properties)) 1.10254 + 1.10255 + if descriptor.interface.hasInterfaceObject(): 1.10256 + cgThings.append(CGDefineDOMInterfaceMethod(descriptor)) 1.10257 + 1.10258 + if ((descriptor.interface.hasInterfaceObject() or descriptor.interface.getNavigatorProperty()) and 1.10259 + not descriptor.interface.isExternal() and 1.10260 + descriptor.isExposedConditionally() and 1.10261 + # Workers stuff is never conditional 1.10262 + not descriptor.workers): 1.10263 + cgThings.append(CGConstructorEnabled(descriptor)) 1.10264 + 1.10265 + if descriptor.concrete: 1.10266 + if descriptor.proxy: 1.10267 + if descriptor.interface.totalMembersInSlots != 0: 1.10268 + raise TypeError("We can't have extra reserved slots for " 1.10269 + "proxy interface %s" % 1.10270 + descriptor.interface.identifier.name) 1.10271 + cgThings.append(CGGeneric(fill( 1.10272 + """ 1.10273 + static_assert(IsBaseOf<nsISupports, ${nativeType} >::value, 1.10274 + "We don't support non-nsISupports native classes for " 1.10275 + "proxy-based bindings yet"); 1.10276 + 1.10277 + """, 1.10278 + nativeType=descriptor.nativeType))) 1.10279 + if not descriptor.wrapperCache: 1.10280 + raise TypeError("We need a wrappercache to support expandos for proxy-based " 1.10281 + "bindings (" + descriptor.name + ")") 1.10282 + handlerThing = CGDOMJSProxyHandler(descriptor) 1.10283 + cgThings.append(CGDOMJSProxyHandlerDeclarer(handlerThing)) 1.10284 + cgThings.append(CGProxyIsProxy(descriptor)) 1.10285 + cgThings.append(CGProxyUnwrap(descriptor)) 1.10286 + cgThings.append(CGDOMJSProxyHandlerDefiner(handlerThing)) 1.10287 + cgThings.append(CGDOMProxyJSClass(descriptor)) 1.10288 + else: 1.10289 + cgThings.append(CGDOMJSClass(descriptor)) 1.10290 + cgThings.append(CGGetJSClassMethod(descriptor)) 1.10291 + if descriptor.interface.hasMembersInSlots(): 1.10292 + if descriptor.interface.hasChildInterfaces(): 1.10293 + raise TypeError("We don't support members in slots on " 1.10294 + "non-leaf interfaces like %s" % 1.10295 + descriptor.interface.identifier.name) 1.10296 + cgThings.append(CGUpdateMemberSlotsMethod(descriptor)) 1.10297 + 1.10298 + if descriptor.interface.getExtendedAttribute("Global"): 1.10299 + assert descriptor.wrapperCache 1.10300 + cgThings.append(CGWrapGlobalMethod(descriptor, properties)) 1.10301 + elif descriptor.wrapperCache: 1.10302 + cgThings.append(CGWrapWithCacheMethod(descriptor, properties)) 1.10303 + cgThings.append(CGWrapMethod(descriptor)) 1.10304 + else: 1.10305 + cgThings.append(CGWrapNonWrapperCacheMethod(descriptor, 1.10306 + properties)) 1.10307 + 1.10308 + # If we're not wrappercached, we don't know how to clear our 1.10309 + # cached values, since we can't get at the JSObject. 1.10310 + if descriptor.wrapperCache: 1.10311 + cgThings.extend(CGClearCachedValueMethod(descriptor, m) for 1.10312 + m in descriptor.interface.members if 1.10313 + m.isAttr() and 1.10314 + # Constants should never need clearing! 1.10315 + not m.getExtendedAttribute("Constant") and 1.10316 + not m.getExtendedAttribute("SameObject") and 1.10317 + m.slotIndex is not None) 1.10318 + 1.10319 + # CGCreateInterfaceObjectsMethod needs to come after our 1.10320 + # CGDOMJSClass, if any. 1.10321 + cgThings.append(CGCreateInterfaceObjectsMethod(descriptor, properties)) 1.10322 + 1.10323 + # CGGetProtoObjectMethod and CGGetConstructorObjectMethod need 1.10324 + # to come after CGCreateInterfaceObjectsMethod. 1.10325 + if descriptor.interface.hasInterfacePrototypeObject(): 1.10326 + cgThings.append(CGGetProtoObjectMethod(descriptor)) 1.10327 + if descriptor.interface.hasInterfaceObject(): 1.10328 + cgThings.append(CGGetConstructorObjectMethod(descriptor)) 1.10329 + 1.10330 + # See whether we need we need to generate an IsPermitted method 1.10331 + if crossOriginGetters or crossOriginSetters or crossOriginMethods: 1.10332 + cgThings.append(CGIsPermittedMethod(descriptor, 1.10333 + crossOriginGetters, 1.10334 + crossOriginSetters, 1.10335 + crossOriginMethods)) 1.10336 + 1.10337 + cgThings = CGList((CGIndenter(t, declareOnly=True) for t in cgThings), "\n") 1.10338 + cgThings = CGWrapper(cgThings, pre='\n', post='\n') 1.10339 + self.cgRoot = CGWrapper(CGNamespace(toBindingNamespace(descriptor.name), 1.10340 + cgThings), 1.10341 + post='\n') 1.10342 + 1.10343 + def declare(self): 1.10344 + return self.cgRoot.declare() 1.10345 + 1.10346 + def define(self): 1.10347 + return self.cgRoot.define() 1.10348 + 1.10349 + def deps(self): 1.10350 + return self._deps 1.10351 + 1.10352 + 1.10353 +class CGNamespacedEnum(CGThing): 1.10354 + def __init__(self, namespace, enumName, names, values, comment=""): 1.10355 + 1.10356 + if not values: 1.10357 + values = [] 1.10358 + 1.10359 + # Account for explicit enum values. 1.10360 + entries = [] 1.10361 + for i in range(0, len(names)): 1.10362 + if len(values) > i and values[i] is not None: 1.10363 + entry = "%s = %s" % (names[i], values[i]) 1.10364 + else: 1.10365 + entry = names[i] 1.10366 + entries.append(entry) 1.10367 + 1.10368 + # Append a Count. 1.10369 + entries.append('_' + enumName + '_Count') 1.10370 + 1.10371 + # Indent. 1.10372 + entries = [' ' + e for e in entries] 1.10373 + 1.10374 + # Build the enum body. 1.10375 + enumstr = comment + 'enum %s\n{\n%s\n};\n' % (enumName, ',\n'.join(entries)) 1.10376 + curr = CGGeneric(declare=enumstr) 1.10377 + 1.10378 + # Add some whitespace padding. 1.10379 + curr = CGWrapper(curr, pre='\n', post='\n') 1.10380 + 1.10381 + # Add the namespace. 1.10382 + curr = CGNamespace(namespace, curr) 1.10383 + 1.10384 + # Add the typedef 1.10385 + typedef = '\ntypedef %s::%s %s;\n\n' % (namespace, enumName, enumName) 1.10386 + curr = CGList([curr, CGGeneric(declare=typedef)]) 1.10387 + 1.10388 + # Save the result. 1.10389 + self.node = curr 1.10390 + 1.10391 + def declare(self): 1.10392 + return self.node.declare() 1.10393 + 1.10394 + def define(self): 1.10395 + return "" 1.10396 + 1.10397 + 1.10398 +class CGDictionary(CGThing): 1.10399 + def __init__(self, dictionary, descriptorProvider): 1.10400 + self.dictionary = dictionary 1.10401 + self.descriptorProvider = descriptorProvider 1.10402 + self.needToInitIds = len(dictionary.members) > 0 1.10403 + self.memberInfo = [ 1.10404 + (member, 1.10405 + getJSToNativeConversionInfo( 1.10406 + member.type, 1.10407 + descriptorProvider, 1.10408 + isEnforceRange=member.enforceRange, 1.10409 + isClamp=member.clamp, 1.10410 + isMember="Dictionary", 1.10411 + isOptional=(not member.defaultValue), 1.10412 + defaultValue=member.defaultValue, 1.10413 + sourceDescription=("'%s' member of %s" % 1.10414 + (member.identifier.name, dictionary.identifier.name)))) 1.10415 + for member in dictionary.members] 1.10416 + 1.10417 + # If we have a union member containing something in the same 1.10418 + # file as us, bail: the C++ includes won't work out. 1.10419 + for member in dictionary.members: 1.10420 + type = member.type.unroll() 1.10421 + if type.isUnion(): 1.10422 + for t in type.flatMemberTypes: 1.10423 + if (t.isDictionary() and 1.10424 + CGHeaders.getDeclarationFilename(t.inner) == 1.10425 + CGHeaders.getDeclarationFilename(dictionary)): 1.10426 + raise TypeError( 1.10427 + "Dictionary contains a union that contains a " 1.10428 + "dictionary in the same WebIDL file. This won't " 1.10429 + "compile. Move the inner dictionary to a " 1.10430 + "different file.\n%s\n%s" % 1.10431 + (t.location, t.inner.location)) 1.10432 + self.structs = self.getStructs() 1.10433 + 1.10434 + def declare(self): 1.10435 + return self.structs.declare() 1.10436 + 1.10437 + def define(self): 1.10438 + return self.structs.define() 1.10439 + 1.10440 + def base(self): 1.10441 + if self.dictionary.parent: 1.10442 + return self.makeClassName(self.dictionary.parent) 1.10443 + return "DictionaryBase" 1.10444 + 1.10445 + def initMethod(self): 1.10446 + body = dedent(""" 1.10447 + // Passing a null JSContext is OK only if we're initing from null, 1.10448 + // Since in that case we will not have to do any property gets 1.10449 + MOZ_ASSERT_IF(!cx, val.isNull()); 1.10450 + """) 1.10451 + 1.10452 + if self.needToInitIds: 1.10453 + body += fill( 1.10454 + """ 1.10455 + ${dictName}Atoms* atomsCache = nullptr; 1.10456 + if (cx) { 1.10457 + atomsCache = GetAtomCache<${dictName}Atoms>(cx); 1.10458 + if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) { 1.10459 + return false; 1.10460 + } 1.10461 + } 1.10462 + 1.10463 + """, 1.10464 + dictName=self.makeClassName(self.dictionary)) 1.10465 + 1.10466 + if self.dictionary.parent: 1.10467 + body += fill( 1.10468 + """ 1.10469 + // Per spec, we init the parent's members first 1.10470 + if (!${dictName}::Init(cx, val)) { 1.10471 + return false; 1.10472 + } 1.10473 + MOZ_ASSERT(IsConvertibleToDictionary(cx, val)); 1.10474 + 1.10475 + """, 1.10476 + dictName=self.makeClassName(self.dictionary.parent)) 1.10477 + else: 1.10478 + body += fill( 1.10479 + """ 1.10480 + if (!IsConvertibleToDictionary(cx, val)) { 1.10481 + return ThrowErrorMessage(cx, MSG_NOT_DICTIONARY, sourceDescription); 1.10482 + } 1.10483 + 1.10484 + """) 1.10485 + 1.10486 + memberInits = [self.getMemberConversion(m).define() 1.10487 + for m in self.memberInfo] 1.10488 + if memberInits: 1.10489 + body += fill( 1.10490 + """ 1.10491 + bool isNull = val.isNullOrUndefined(); 1.10492 + // We only need these if !isNull, in which case we have |cx|. 1.10493 + Maybe<JS::Rooted<JSObject *> > object; 1.10494 + Maybe<JS::Rooted<JS::Value> > temp; 1.10495 + if (!isNull) { 1.10496 + object.construct(cx, &val.toObject()); 1.10497 + temp.construct(cx); 1.10498 + } 1.10499 + $*{memberInits} 1.10500 + """, 1.10501 + memberInits="\n".join(memberInits)) 1.10502 + 1.10503 + body += "return true;\n" 1.10504 + 1.10505 + return ClassMethod("Init", "bool", [ 1.10506 + Argument('JSContext*', 'cx'), 1.10507 + Argument('JS::Handle<JS::Value>', 'val'), 1.10508 + Argument('const char*', 'sourceDescription', default='"Value"') 1.10509 + ], body=body) 1.10510 + 1.10511 + def initFromJSONMethod(self): 1.10512 + return ClassMethod( 1.10513 + "Init", "bool", 1.10514 + [Argument('const nsAString&', 'aJSON')], 1.10515 + body=dedent(""" 1.10516 + MOZ_ASSERT(NS_IsMainThread()); 1.10517 + AutoSafeJSContext cx; 1.10518 + JS::Rooted<JS::Value> json(cx); 1.10519 + bool ok = ParseJSON(cx, aJSON, &json); 1.10520 + NS_ENSURE_TRUE(ok, false); 1.10521 + return Init(cx, json); 1.10522 + """)) 1.10523 + 1.10524 + def toObjectMethod(self): 1.10525 + body = "" 1.10526 + if self.needToInitIds: 1.10527 + body += fill( 1.10528 + """ 1.10529 + ${dictName}Atoms* atomsCache = GetAtomCache<${dictName}Atoms>(cx); 1.10530 + if (!*reinterpret_cast<jsid**>(atomsCache) && !InitIds(cx, atomsCache)) { 1.10531 + return false; 1.10532 + } 1.10533 + 1.10534 + """, 1.10535 + dictName=self.makeClassName(self.dictionary)) 1.10536 + 1.10537 + if self.dictionary.parent: 1.10538 + body += fill( 1.10539 + """ 1.10540 + // Per spec, we define the parent's members first 1.10541 + if (!${dictName}::ToObject(cx, rval)) { 1.10542 + return false; 1.10543 + } 1.10544 + JS::Rooted<JSObject*> obj(cx, &rval.toObject()); 1.10545 + 1.10546 + """, 1.10547 + dictName=self.makeClassName(self.dictionary.parent)) 1.10548 + else: 1.10549 + body += fill( 1.10550 + """ 1.10551 + JS::Rooted<JSObject*> obj(cx, JS_NewObject(cx, nullptr, JS::NullPtr(), JS::NullPtr())); 1.10552 + if (!obj) { 1.10553 + return false; 1.10554 + } 1.10555 + rval.set(JS::ObjectValue(*obj)); 1.10556 + 1.10557 + """) 1.10558 + 1.10559 + if self.memberInfo: 1.10560 + body += "\n".join(self.getMemberDefinition(m).define() 1.10561 + for m in self.memberInfo) 1.10562 + else: 1.10563 + body += "\n" # BOGUS extra blank line 1.10564 + body += "\nreturn true;\n" 1.10565 + 1.10566 + return ClassMethod("ToObject", "bool", [ 1.10567 + Argument('JSContext*', 'cx'), 1.10568 + Argument('JS::MutableHandle<JS::Value>', 'rval'), 1.10569 + ], const=True, body=body) 1.10570 + 1.10571 + def initIdsMethod(self): 1.10572 + assert self.needToInitIds 1.10573 + idinit = ['!atomsCache->%s.init(cx, "%s")' % 1.10574 + (CGDictionary.makeIdName(m.identifier.name), 1.10575 + m.identifier.name) 1.10576 + for m in self.dictionary.members] 1.10577 + idinit.reverse() 1.10578 + body = fill( 1.10579 + """ 1.10580 + MOZ_ASSERT(!*reinterpret_cast<jsid**>(atomsCache)); 1.10581 + 1.10582 + // Initialize these in reverse order so that any failure leaves the first one 1.10583 + // uninitialized. 1.10584 + if (${idinit}) { 1.10585 + return false; 1.10586 + } 1.10587 + return true; 1.10588 + """, 1.10589 + idinit=" ||\n ".join(idinit)) 1.10590 + 1.10591 + return ClassMethod("InitIds", "bool", [ 1.10592 + Argument("JSContext*", "cx"), 1.10593 + Argument("%sAtoms*" % self.makeClassName(self.dictionary), 1.10594 + "atomsCache"), 1.10595 + ], static=True, body=body, visibility="private") 1.10596 + 1.10597 + def traceDictionaryMethod(self): 1.10598 + body = "" 1.10599 + if self.dictionary.parent: 1.10600 + cls = self.makeClassName(self.dictionary.parent) 1.10601 + body += "%s::TraceDictionary(trc);\n" % cls 1.10602 + 1.10603 + memberTraces = [self.getMemberTrace(m) 1.10604 + for m in self.dictionary.members 1.10605 + if typeNeedsRooting(m.type)] 1.10606 + 1.10607 + if memberTraces: 1.10608 + body += "\n".join(memberTraces) 1.10609 + else: 1.10610 + body += "\n" # BOGUS extra newline 1.10611 + 1.10612 + return ClassMethod("TraceDictionary", "void", [ 1.10613 + Argument("JSTracer*", "trc"), 1.10614 + ], body=body) 1.10615 + 1.10616 + def assignmentOperator(self): 1.10617 + body = CGList([]) 1.10618 + if self.dictionary.parent: 1.10619 + body.append(CGGeneric( 1.10620 + "%s::operator=(aOther);\n" % 1.10621 + self.makeClassName(self.dictionary.parent))) 1.10622 + for m, _ in self.memberInfo: 1.10623 + memberName = self.makeMemberName(m.identifier.name) 1.10624 + if not m.defaultValue: 1.10625 + memberAssign = CGGeneric(fill( 1.10626 + """ 1.10627 + if (aOther.${name}.WasPassed()) { 1.10628 + ${name}.Construct(); 1.10629 + ${name}.Value() = aOther.${name}.Value(); 1.10630 + } else { 1.10631 + ${name}.Reset(); 1.10632 + } 1.10633 + """, 1.10634 + name=memberName)) 1.10635 + else: 1.10636 + memberAssign = CGGeneric( 1.10637 + "%s = aOther.%s;\n" % (memberName, memberName)) 1.10638 + body.append(memberAssign) 1.10639 + return ClassMethod( 1.10640 + "operator=", "void", 1.10641 + [Argument("const %s&" % self.makeClassName(self.dictionary), 1.10642 + "aOther")], 1.10643 + body=body.define() or "\n") # BOGUS blank line when empty 1.10644 + 1.10645 + def getStructs(self): 1.10646 + d = self.dictionary 1.10647 + selfName = self.makeClassName(d) 1.10648 + members = [ClassMember(self.makeMemberName(m[0].identifier.name), 1.10649 + self.getMemberType(m), 1.10650 + visibility="public", 1.10651 + body=self.getMemberInitializer(m)) 1.10652 + for m in self.memberInfo] 1.10653 + ctors = [ 1.10654 + ClassConstructor( 1.10655 + [], 1.10656 + visibility="public", 1.10657 + body=( 1.10658 + "// Safe to pass a null context if we pass a null value\n" 1.10659 + "Init(nullptr, JS::NullHandleValue);\n")), 1.10660 + ClassConstructor( 1.10661 + [Argument("int", "")], 1.10662 + visibility="protected", 1.10663 + explicit=True, 1.10664 + bodyInHeader=True, 1.10665 + body='// Do nothing here; this is used by our "Fast" subclass\n') 1.10666 + ] 1.10667 + methods = [] 1.10668 + 1.10669 + if self.needToInitIds: 1.10670 + methods.append(self.initIdsMethod()) 1.10671 + 1.10672 + methods.append(self.initMethod()) 1.10673 + methods.append(self.initFromJSONMethod()) 1.10674 + try: 1.10675 + methods.append(self.toObjectMethod()) 1.10676 + except MethodNotNewObjectError: 1.10677 + # If we can't have a ToObject() because one of our members can only 1.10678 + # be returned from [NewObject] methods, then just skip generating 1.10679 + # ToObject(). 1.10680 + pass 1.10681 + methods.append(self.traceDictionaryMethod()) 1.10682 + 1.10683 + if CGDictionary.isDictionaryCopyConstructible(d): 1.10684 + disallowCopyConstruction = False 1.10685 + # Note: no base constructors because our operator= will 1.10686 + # deal with that. 1.10687 + ctors.append(ClassConstructor([Argument("const %s&" % selfName, 1.10688 + "aOther")], 1.10689 + bodyInHeader=True, 1.10690 + visibility="public", 1.10691 + explicit=True, 1.10692 + body="*this = aOther;\n")) 1.10693 + methods.append(self.assignmentOperator()) 1.10694 + else: 1.10695 + disallowCopyConstruction = True 1.10696 + 1.10697 + struct = CGClass(selfName, 1.10698 + bases=[ClassBase(self.base())], 1.10699 + members=members, 1.10700 + constructors=ctors, 1.10701 + methods=methods, 1.10702 + isStruct=True, 1.10703 + disallowCopyConstruction=disallowCopyConstruction) 1.10704 + 1.10705 + fastDictionaryCtor = ClassConstructor( 1.10706 + [], 1.10707 + visibility="public", 1.10708 + bodyInHeader=True, 1.10709 + baseConstructors=["%s(42)" % selfName], 1.10710 + body="// Doesn't matter what int we pass to the parent constructor\n") 1.10711 + 1.10712 + fastStruct = CGClass("Fast" + selfName, 1.10713 + bases=[ClassBase(selfName)], 1.10714 + constructors=[fastDictionaryCtor], 1.10715 + isStruct=True) 1.10716 + 1.10717 + return CGList([struct, 1.10718 + CGNamespace('binding_detail', fastStruct)], 1.10719 + "\n") 1.10720 + 1.10721 + def deps(self): 1.10722 + return self.dictionary.getDeps() 1.10723 + 1.10724 + @staticmethod 1.10725 + def makeDictionaryName(dictionary): 1.10726 + return dictionary.identifier.name 1.10727 + 1.10728 + def makeClassName(self, dictionary): 1.10729 + return self.makeDictionaryName(dictionary) 1.10730 + 1.10731 + @staticmethod 1.10732 + def makeMemberName(name): 1.10733 + return "m" + name[0].upper() + name[1:] 1.10734 + 1.10735 + def getMemberType(self, memberInfo): 1.10736 + _, conversionInfo = memberInfo 1.10737 + # We can't handle having a holderType here 1.10738 + assert conversionInfo.holderType is None 1.10739 + declType = conversionInfo.declType 1.10740 + if conversionInfo.dealWithOptional: 1.10741 + declType = CGTemplatedType("Optional", declType) 1.10742 + return declType.define() 1.10743 + 1.10744 + def getMemberConversion(self, memberInfo): 1.10745 + member, conversionInfo = memberInfo 1.10746 + replacements = { 1.10747 + "val": "temp.ref()", 1.10748 + "mutableVal": "&temp.ref()", 1.10749 + "declName": self.makeMemberName(member.identifier.name), 1.10750 + # We need a holder name for external interfaces, but 1.10751 + # it's scoped down to the conversion so we can just use 1.10752 + # anything we want. 1.10753 + "holderName": "holder" 1.10754 + } 1.10755 + # We can't handle having a holderType here 1.10756 + assert conversionInfo.holderType is None 1.10757 + if conversionInfo.dealWithOptional: 1.10758 + replacements["declName"] = "(" + replacements["declName"] + ".Value())" 1.10759 + if member.defaultValue: 1.10760 + replacements["haveValue"] = "!isNull && !temp.ref().isUndefined()" 1.10761 + 1.10762 + propId = self.makeIdName(member.identifier.name) 1.10763 + propGet = ("JS_GetPropertyById(cx, object.ref(), atomsCache->%s, &temp.ref())" % 1.10764 + propId) 1.10765 + 1.10766 + conversionReplacements = { 1.10767 + "prop": self.makeMemberName(member.identifier.name), 1.10768 + "convert": string.Template(conversionInfo.template).substitute(replacements), 1.10769 + "propGet": propGet 1.10770 + } 1.10771 + conversion = ("if (!isNull && !${propGet}) {\n" 1.10772 + " return false;\n" 1.10773 + "}\n") 1.10774 + if member.defaultValue: 1.10775 + conversion += "${convert}" 1.10776 + else: 1.10777 + conversion += ( 1.10778 + "if (!isNull && !temp.ref().isUndefined()) {\n" 1.10779 + " ${prop}.Construct();\n" 1.10780 + "${convert}" 1.10781 + "}\n") 1.10782 + conversionReplacements["convert"] = indent(conversionReplacements["convert"]) 1.10783 + 1.10784 + return CGGeneric( 1.10785 + string.Template(conversion).substitute(conversionReplacements)) 1.10786 + 1.10787 + def getMemberDefinition(self, memberInfo): 1.10788 + member = memberInfo[0] 1.10789 + declType = memberInfo[1].declType 1.10790 + memberLoc = self.makeMemberName(member.identifier.name) 1.10791 + if member.defaultValue: 1.10792 + memberData = memberLoc 1.10793 + else: 1.10794 + # The data is inside the Optional<> 1.10795 + memberData = "%s.InternalValue()" % memberLoc 1.10796 + 1.10797 + # If you have to change this list (which you shouldn't!), make sure it 1.10798 + # continues to match the list in test_Object.prototype_props.html 1.10799 + if (member.identifier.name in 1.10800 + ["constructor", "toSource", "toString", "toLocaleString", "valueOf", 1.10801 + "watch", "unwatch", "hasOwnProperty", "isPrototypeOf", 1.10802 + "propertyIsEnumerable", "__defineGetter__", "__defineSetter__", 1.10803 + "__lookupGetter__", "__lookupSetter__", "__proto__"]): 1.10804 + raise TypeError("'%s' member of %s dictionary shadows " 1.10805 + "a property of Object.prototype, and Xrays to " 1.10806 + "Object can't handle that.\n" 1.10807 + "%s" % 1.10808 + (member.identifier.name, 1.10809 + self.dictionary.identifier.name, 1.10810 + member.location)) 1.10811 + 1.10812 + propDef = ( 1.10813 + 'JS_DefinePropertyById(cx, obj, atomsCache->%s, temp, nullptr, nullptr, JSPROP_ENUMERATE)' % 1.10814 + self.makeIdName(member.identifier.name)) 1.10815 + 1.10816 + innerTemplate = wrapForType( 1.10817 + member.type, self.descriptorProvider, 1.10818 + { 1.10819 + 'result': "currentValue", 1.10820 + 'successCode': ("if (!%s) {\n" 1.10821 + " return false;\n" 1.10822 + "}\n" 1.10823 + "break;\n" % propDef), 1.10824 + 'jsvalRef': "temp", 1.10825 + 'jsvalHandle': "&temp", 1.10826 + 'returnsNewObject': False, 1.10827 + # 'obj' can just be allowed to be the string "obj", since that 1.10828 + # will be our dictionary object, which is presumably itself in 1.10829 + # the right scope. 1.10830 + 'typedArraysAreStructs': True 1.10831 + }) 1.10832 + conversion = CGGeneric(innerTemplate) 1.10833 + conversion = CGWrapper(conversion, 1.10834 + pre=("JS::Rooted<JS::Value> temp(cx);\n" 1.10835 + "%s const & currentValue = %s;\n" % 1.10836 + (declType.define(), memberData) 1.10837 + )) 1.10838 + 1.10839 + # Now make sure that our successCode can actually break out of the 1.10840 + # conversion. This incidentally gives us a scope for 'temp' and 1.10841 + # 'currentValue'. 1.10842 + conversion = CGWrapper( 1.10843 + CGIndenter(conversion), 1.10844 + pre=("do {\n" 1.10845 + " // block for our 'break' successCode and scope for 'temp' and 'currentValue'\n"), 1.10846 + post="} while(0);\n") 1.10847 + if not member.defaultValue: 1.10848 + # Only do the conversion if we have a value 1.10849 + conversion = CGIfWrapper(conversion, "%s.WasPassed()" % memberLoc) 1.10850 + return conversion 1.10851 + 1.10852 + def getMemberTrace(self, member): 1.10853 + type = member.type 1.10854 + assert typeNeedsRooting(type) 1.10855 + memberLoc = self.makeMemberName(member.identifier.name) 1.10856 + if member.defaultValue: 1.10857 + memberData = memberLoc 1.10858 + else: 1.10859 + # The data is inside the Optional<> 1.10860 + memberData = "%s.Value()" % memberLoc 1.10861 + 1.10862 + memberName = "%s.%s" % (self.makeClassName(self.dictionary), 1.10863 + memberLoc) 1.10864 + 1.10865 + if type.isObject(): 1.10866 + trace = CGGeneric('JS_CallObjectTracer(trc, %s, "%s");\n' % 1.10867 + ("&"+memberData, memberName)) 1.10868 + if type.nullable(): 1.10869 + trace = CGIfWrapper(trace, memberData) 1.10870 + elif type.isAny(): 1.10871 + trace = CGGeneric('JS_CallValueTracer(trc, %s, "%s");\n' % 1.10872 + ("&"+memberData, memberName)) 1.10873 + elif (type.isSequence() or type.isDictionary() or 1.10874 + type.isSpiderMonkeyInterface() or type.isUnion()): 1.10875 + if type.nullable(): 1.10876 + memberNullable = memberData 1.10877 + memberData = "%s.Value()" % memberData 1.10878 + if type.isSequence(): 1.10879 + trace = CGGeneric('DoTraceSequence(trc, %s);\n' % memberData) 1.10880 + elif type.isDictionary(): 1.10881 + trace = CGGeneric('%s.TraceDictionary(trc);\n' % memberData) 1.10882 + elif type.isUnion(): 1.10883 + trace = CGGeneric('%s.TraceUnion(trc);\n' % memberData) 1.10884 + else: 1.10885 + assert type.isSpiderMonkeyInterface() 1.10886 + trace = CGGeneric('%s.TraceSelf(trc);\n' % memberData) 1.10887 + if type.nullable(): 1.10888 + trace = CGIfWrapper(trace, "!%s.IsNull()" % memberNullable) 1.10889 + else: 1.10890 + assert False # unknown type 1.10891 + 1.10892 + if not member.defaultValue: 1.10893 + trace = CGIfWrapper(trace, "%s.WasPassed()" % memberLoc) 1.10894 + 1.10895 + return trace.define() 1.10896 + 1.10897 + def getMemberInitializer(self, memberInfo): 1.10898 + """ 1.10899 + Get the right initializer for the member. Most members don't need one, 1.10900 + but we need to pre-initialize 'any' and 'object' that have a default 1.10901 + value, so they're safe to trace at all times. 1.10902 + """ 1.10903 + member, _ = memberInfo 1.10904 + if not member.defaultValue: 1.10905 + # No default value means no need to set it up front, since it's 1.10906 + # inside an Optional and won't get traced until it's actually set 1.10907 + # up. 1.10908 + return None 1.10909 + type = member.type 1.10910 + if type.isAny(): 1.10911 + return "JS::UndefinedValue()" 1.10912 + if type.isObject(): 1.10913 + return "nullptr" 1.10914 + return None 1.10915 + 1.10916 + @staticmethod 1.10917 + def makeIdName(name): 1.10918 + return name + "_id" 1.10919 + 1.10920 + @staticmethod 1.10921 + def getDictionaryDependenciesFromType(type): 1.10922 + if type.isDictionary(): 1.10923 + return set([type.unroll().inner]) 1.10924 + if type.isSequence() or type.isArray(): 1.10925 + return CGDictionary.getDictionaryDependenciesFromType(type.unroll()) 1.10926 + return set() 1.10927 + 1.10928 + @staticmethod 1.10929 + def getDictionaryDependencies(dictionary): 1.10930 + deps = set() 1.10931 + if dictionary.parent: 1.10932 + deps.add(dictionary.parent) 1.10933 + for member in dictionary.members: 1.10934 + deps |= CGDictionary.getDictionaryDependenciesFromType(member.type) 1.10935 + return deps 1.10936 + 1.10937 + @staticmethod 1.10938 + def isDictionaryCopyConstructible(dictionary): 1.10939 + if (dictionary.parent and 1.10940 + not CGDictionary.isDictionaryCopyConstructible(dictionary.parent)): 1.10941 + return False 1.10942 + return all(isTypeCopyConstructible(m.type) for m in dictionary.members) 1.10943 + 1.10944 + 1.10945 +class CGRegisterProtos(CGAbstractMethod): 1.10946 + def __init__(self, config): 1.10947 + CGAbstractMethod.__init__(self, None, 'Register', 'void', 1.10948 + [Argument('nsScriptNameSpaceManager*', 'aNameSpaceManager')]) 1.10949 + self.config = config 1.10950 + 1.10951 + def _defineMacro(self): 1.10952 + return dedent(""" 1.10953 + #define REGISTER_PROTO(_dom_class, _ctor_check) \\ 1.10954 + aNameSpaceManager->RegisterDefineDOMInterface(MOZ_UTF16(#_dom_class), _dom_class##Binding::DefineDOMInterface, _ctor_check); 1.10955 + #define REGISTER_CONSTRUCTOR(_dom_constructor, _dom_class, _ctor_check) \\ 1.10956 + aNameSpaceManager->RegisterDefineDOMInterface(MOZ_UTF16(#_dom_constructor), _dom_class##Binding::DefineDOMInterface, _ctor_check); 1.10957 + #define REGISTER_NAVIGATOR_CONSTRUCTOR(_prop, _dom_class, _ctor_check) \\ 1.10958 + aNameSpaceManager->RegisterNavigatorDOMConstructor(MOZ_UTF16(_prop), _dom_class##Binding::ConstructNavigatorObject, _ctor_check); 1.10959 + """) 1.10960 + 1.10961 + def _undefineMacro(self): 1.10962 + return dedent(""" 1.10963 + #undef REGISTER_CONSTRUCTOR 1.10964 + #undef REGISTER_PROTO 1.10965 + #undef REGISTER_NAVIGATOR_CONSTRUCTOR 1.10966 + """) 1.10967 + 1.10968 + def _registerProtos(self): 1.10969 + def getCheck(desc): 1.10970 + if not desc.isExposedConditionally(): 1.10971 + return "nullptr" 1.10972 + return "%sBinding::ConstructorEnabled" % desc.name 1.10973 + lines = [] 1.10974 + for desc in self.config.getDescriptors(hasInterfaceObject=True, 1.10975 + isExternal=False, 1.10976 + workers=False, 1.10977 + register=True): 1.10978 + lines.append("REGISTER_PROTO(%s, %s);\n" % (desc.name, getCheck(desc))) 1.10979 + lines.extend("REGISTER_CONSTRUCTOR(%s, %s, %s);\n" % (n.identifier.name, desc.name, getCheck(desc)) 1.10980 + for n in desc.interface.namedConstructors) 1.10981 + for desc in self.config.getDescriptors(isNavigatorProperty=True, register=True): 1.10982 + propName = desc.interface.getNavigatorProperty() 1.10983 + assert propName 1.10984 + lines.append('REGISTER_NAVIGATOR_CONSTRUCTOR("%s", %s, %s);\n' % (propName, desc.name, getCheck(desc))) 1.10985 + return ''.join(lines) 1.10986 + 1.10987 + def definition_body(self): 1.10988 + return "\n" + self._defineMacro() + "\n" + self._registerProtos() + "\n" + self._undefineMacro() 1.10989 + 1.10990 + 1.10991 +def dependencySortObjects(objects, dependencyGetter, nameGetter): 1.10992 + """ 1.10993 + Sort IDL objects with dependencies on each other such that if A 1.10994 + depends on B then B will come before A. This is needed for 1.10995 + declaring C++ classes in the right order, for example. Objects 1.10996 + that have no dependencies are just sorted by name. 1.10997 + 1.10998 + objects should be something that can produce a set of objects 1.10999 + (e.g. a set, iterator, list, etc). 1.11000 + 1.11001 + dependencyGetter is something that, given an object, should return 1.11002 + the set of objects it depends on. 1.11003 + """ 1.11004 + # XXXbz this will fail if we have two webidl files F1 and F2 such that F1 1.11005 + # declares an object which depends on an object in F2, and F2 declares an 1.11006 + # object (possibly a different one!) that depends on an object in F1. The 1.11007 + # good news is that I expect this to never happen. 1.11008 + sortedObjects = [] 1.11009 + objects = set(objects) 1.11010 + while len(objects) != 0: 1.11011 + # Find the dictionaries that don't depend on anything else 1.11012 + # anymore and move them over. 1.11013 + toMove = [o for o in objects if 1.11014 + len(dependencyGetter(o) & objects) == 0] 1.11015 + if len(toMove) == 0: 1.11016 + raise TypeError("Loop in dependency graph\n" + 1.11017 + "\n".join(o.location for o in objects)) 1.11018 + objects = objects - set(toMove) 1.11019 + sortedObjects.extend(sorted(toMove, key=nameGetter)) 1.11020 + return sortedObjects 1.11021 + 1.11022 + 1.11023 +class ForwardDeclarationBuilder: 1.11024 + """ 1.11025 + Create a canonical representation of a set of namespaced forward 1.11026 + declarations. 1.11027 + """ 1.11028 + def __init__(self): 1.11029 + """ 1.11030 + The set of declarations is represented as a tree of nested namespaces. 1.11031 + Each tree node has a set of declarations |decls| and a dict |children|. 1.11032 + Each declaration is a pair consisting of the class name and a boolean 1.11033 + that is true iff the class is really a struct. |children| maps the 1.11034 + names of inner namespaces to the declarations in that namespace. 1.11035 + """ 1.11036 + self.decls = set() 1.11037 + self.children = {} 1.11038 + 1.11039 + def _listAdd(self, namespaces, name, isStruct=False): 1.11040 + """ 1.11041 + Add a forward declaration, where |namespaces| is a list of namespaces. 1.11042 + |name| should not contain any other namespaces. 1.11043 + """ 1.11044 + if namespaces: 1.11045 + child = self.children.setdefault(namespaces[0], ForwardDeclarationBuilder()) 1.11046 + child._listAdd(namespaces[1:], name, isStruct) 1.11047 + else: 1.11048 + assert '::' not in name 1.11049 + self.decls.add((name, isStruct)) 1.11050 + 1.11051 + def addInMozillaDom(self, name, isStruct=False): 1.11052 + """ 1.11053 + Add a forward declaration to the mozilla::dom:: namespace. |name| should not 1.11054 + contain any other namespaces. 1.11055 + """ 1.11056 + self._listAdd(["mozilla", "dom"], name, isStruct) 1.11057 + 1.11058 + def add(self, nativeType, isStruct=False): 1.11059 + """ 1.11060 + Add a forward declaration, where |nativeType| is a string containing 1.11061 + the type and its namespaces, in the usual C++ way. 1.11062 + """ 1.11063 + components = nativeType.split('::') 1.11064 + self._listAdd(components[:-1], components[-1], isStruct) 1.11065 + 1.11066 + def _build(self, atTopLevel): 1.11067 + """ 1.11068 + Return a codegenerator for the forward declarations. 1.11069 + """ 1.11070 + decls = [] 1.11071 + if self.decls: 1.11072 + decls.append(CGList([CGClassForwardDeclare(cname, isStruct) 1.11073 + for cname, isStruct in sorted(self.decls)])) 1.11074 + for namespace, child in sorted(self.children.iteritems()): 1.11075 + decls.append(CGNamespace(namespace, child._build(atTopLevel=False), declareOnly=True)) 1.11076 + 1.11077 + cg = CGList(decls, "\n") 1.11078 + if not atTopLevel and len(decls) + len(self.decls) > 1: 1.11079 + cg = CGWrapper(cg, pre='\n', post='\n') 1.11080 + return cg 1.11081 + 1.11082 + def build(self): 1.11083 + return self._build(atTopLevel=True) 1.11084 + 1.11085 + 1.11086 +class CGForwardDeclarations(CGWrapper): 1.11087 + """ 1.11088 + Code generate the forward declarations for a header file. 1.11089 + """ 1.11090 + def __init__(self, config, descriptors, mainCallbacks, workerCallbacks, 1.11091 + dictionaries, callbackInterfaces): 1.11092 + builder = ForwardDeclarationBuilder() 1.11093 + 1.11094 + def forwardDeclareForType(t, workerness='both'): 1.11095 + t = t.unroll() 1.11096 + if t.isGeckoInterface(): 1.11097 + name = t.inner.identifier.name 1.11098 + # Find and add the non-worker implementation, if any. 1.11099 + if workerness != 'workeronly': 1.11100 + try: 1.11101 + desc = config.getDescriptor(name, False) 1.11102 + builder.add(desc.nativeType) 1.11103 + except NoSuchDescriptorError: 1.11104 + pass 1.11105 + # Find and add the worker implementation, if any. 1.11106 + if workerness != 'mainthreadonly': 1.11107 + try: 1.11108 + desc = config.getDescriptor(name, True) 1.11109 + builder.add(desc.nativeType) 1.11110 + except NoSuchDescriptorError: 1.11111 + pass 1.11112 + elif t.isCallback(): 1.11113 + builder.addInMozillaDom(str(t)) 1.11114 + elif t.isDictionary(): 1.11115 + builder.addInMozillaDom(t.inner.identifier.name, isStruct=True) 1.11116 + elif t.isCallbackInterface(): 1.11117 + builder.addInMozillaDom(t.inner.identifier.name) 1.11118 + elif t.isUnion(): 1.11119 + # Forward declare both the owning and non-owning version, 1.11120 + # since we don't know which one we might want 1.11121 + builder.addInMozillaDom(CGUnionStruct.unionTypeName(t, False)) 1.11122 + builder.addInMozillaDom(CGUnionStruct.unionTypeName(t, True)) 1.11123 + elif t.isMozMap(): 1.11124 + forwardDeclareForType(t.inner, workerness) 1.11125 + # Don't need to do anything for void, primitive, string, any or object. 1.11126 + # There may be some other cases we are missing. 1.11127 + 1.11128 + # Needed for at least Wrap. 1.11129 + for d in descriptors: 1.11130 + builder.add(d.nativeType) 1.11131 + 1.11132 + # We just about always need NativePropertyHooks 1.11133 + builder.addInMozillaDom("NativePropertyHooks") 1.11134 + builder.addInMozillaDom("ProtoAndIfaceCache") 1.11135 + 1.11136 + for callback in mainCallbacks: 1.11137 + forwardDeclareForType(callback) 1.11138 + for t in getTypesFromCallback(callback): 1.11139 + forwardDeclareForType(t, workerness='mainthreadonly') 1.11140 + 1.11141 + for callback in workerCallbacks: 1.11142 + forwardDeclareForType(callback) 1.11143 + for t in getTypesFromCallback(callback): 1.11144 + forwardDeclareForType(t, workerness='workeronly') 1.11145 + 1.11146 + for d in callbackInterfaces: 1.11147 + builder.add(d.nativeType) 1.11148 + for t in getTypesFromDescriptor(d): 1.11149 + forwardDeclareForType(t) 1.11150 + 1.11151 + for d in dictionaries: 1.11152 + if len(d.members) > 0: 1.11153 + builder.addInMozillaDom(d.identifier.name + "Atoms", isStruct=True) 1.11154 + for t in getTypesFromDictionary(d): 1.11155 + forwardDeclareForType(t) 1.11156 + 1.11157 + CGWrapper.__init__(self, builder.build()) 1.11158 + 1.11159 + 1.11160 +class CGBindingRoot(CGThing): 1.11161 + """ 1.11162 + Root codegen class for binding generation. Instantiate the class, and call 1.11163 + declare or define to generate header or cpp code (respectively). 1.11164 + """ 1.11165 + def __init__(self, config, prefix, webIDLFile): 1.11166 + bindingHeaders = {} 1.11167 + descriptors = config.getDescriptors(webIDLFile=webIDLFile, 1.11168 + hasInterfaceOrInterfacePrototypeObject=True, 1.11169 + skipGen=False) 1.11170 + 1.11171 + def descriptorRequiresPreferences(desc): 1.11172 + iface = desc.interface 1.11173 + return any(m.getExtendedAttribute("Pref") for m in iface.members + [iface]) 1.11174 + 1.11175 + bindingHeaders["mozilla/Preferences.h"] = any( 1.11176 + descriptorRequiresPreferences(d) for d in descriptors) 1.11177 + bindingHeaders["mozilla/dom/NonRefcountedDOMObject.h"] = any( 1.11178 + d.nativeOwnership == 'owned' for d in descriptors) 1.11179 + bindingHeaders["mozilla/dom/DOMJSProxyHandler.h"] = any( 1.11180 + d.concrete and d.proxy for d in descriptors) 1.11181 + 1.11182 + def descriptorHasChromeOnly(desc): 1.11183 + return (any(isChromeOnly(a) for a in desc.interface.members) or 1.11184 + desc.interface.getExtendedAttribute("ChromeOnly") is not None or 1.11185 + # JS-implemented interfaces with an interface object get a 1.11186 + # chromeonly _create method. 1.11187 + (desc.interface.isJSImplemented() and 1.11188 + desc.interface.hasInterfaceObject())) 1.11189 + 1.11190 + bindingHeaders["nsContentUtils.h"] = any( 1.11191 + descriptorHasChromeOnly(d) for d in descriptors) 1.11192 + # XXXkhuey ugly hack but this is going away soon. 1.11193 + bindingHeaders['xpcprivate.h'] = webIDLFile.endswith("EventTarget.webidl") 1.11194 + hasWorkerStuff = len(config.getDescriptors(webIDLFile=webIDLFile, 1.11195 + workers=True)) != 0 1.11196 + bindingHeaders["WorkerPrivate.h"] = hasWorkerStuff 1.11197 + bindingHeaders["nsThreadUtils.h"] = hasWorkerStuff 1.11198 + 1.11199 + dictionaries = config.getDictionaries(webIDLFile=webIDLFile) 1.11200 + bindingHeaders["nsCxPusher.h"] = dictionaries 1.11201 + bindingHeaders["AtomList.h"] = any( 1.11202 + len(dict.members) > 0 for dict in dictionaries) 1.11203 + mainCallbacks = config.getCallbacks(webIDLFile=webIDLFile, 1.11204 + workers=False) 1.11205 + workerCallbacks = config.getCallbacks(webIDLFile=webIDLFile, 1.11206 + workers=True) 1.11207 + callbackDescriptors = config.getDescriptors(webIDLFile=webIDLFile, 1.11208 + isCallback=True) 1.11209 + jsImplemented = config.getDescriptors(webIDLFile=webIDLFile, 1.11210 + isJSImplemented=True) 1.11211 + bindingHeaders["nsPIDOMWindow.h"] = jsImplemented 1.11212 + 1.11213 + def addHeaderBasedOnTypes(header, typeChecker): 1.11214 + bindingHeaders[header] = ( 1.11215 + bindingHeaders.get(header, False) or 1.11216 + any(map(typeChecker, 1.11217 + getAllTypes(descriptors + callbackDescriptors, 1.11218 + dictionaries, 1.11219 + mainCallbacks + workerCallbacks)))) 1.11220 + 1.11221 + bindingHeaders["nsDOMQS.h"] = any(d.hasXPConnectImpls for d in descriptors) 1.11222 + # Only mainthread things can have hasXPConnectImpls 1.11223 + provider = config.getDescriptorProvider(False) 1.11224 + 1.11225 + def checkForXPConnectImpls(typeInfo): 1.11226 + type, _, _ = typeInfo 1.11227 + type = type.unroll() 1.11228 + while type.isMozMap(): 1.11229 + type = type.inner.unroll() 1.11230 + if not type.isInterface() or not type.isGeckoInterface(): 1.11231 + return False 1.11232 + try: 1.11233 + typeDesc = provider.getDescriptor(type.inner.identifier.name) 1.11234 + except NoSuchDescriptorError: 1.11235 + return False 1.11236 + return typeDesc.hasXPConnectImpls 1.11237 + addHeaderBasedOnTypes("nsDOMQS.h", checkForXPConnectImpls) 1.11238 + 1.11239 + def descriptorClearsPropsInSlots(descriptor): 1.11240 + if not descriptor.wrapperCache: 1.11241 + return False 1.11242 + return any(m.isAttr() and m.getExtendedAttribute("StoreInSlot") 1.11243 + for m in descriptor.interface.members) 1.11244 + bindingHeaders["nsJSUtils.h"] = any(descriptorClearsPropsInSlots(d) for d in descriptors) 1.11245 + 1.11246 + # Do codegen for all the enums 1.11247 + enums = config.getEnums(webIDLFile) 1.11248 + cgthings = [CGEnum(e) for e in enums] 1.11249 + 1.11250 + hasCode = (descriptors or callbackDescriptors or dictionaries or 1.11251 + mainCallbacks or workerCallbacks) 1.11252 + bindingHeaders["mozilla/dom/BindingUtils.h"] = hasCode 1.11253 + bindingHeaders["mozilla/dom/OwningNonNull.h"] = hasCode 1.11254 + bindingHeaders["mozilla/dom/BindingDeclarations.h"] = ( 1.11255 + not hasCode and enums) 1.11256 + 1.11257 + bindingHeaders["WrapperFactory.h"] = descriptors 1.11258 + bindingHeaders["mozilla/dom/DOMJSClass.h"] = descriptors 1.11259 + 1.11260 + # Do codegen for all the dictionaries. We have to be a bit careful 1.11261 + # here, because we have to generate these in order from least derived 1.11262 + # to most derived so that class inheritance works out. We also have to 1.11263 + # generate members before the dictionary that contains them. 1.11264 + cgthings.extend([CGDictionary(d, config.getDescriptorProvider(False)) 1.11265 + for d in 1.11266 + dependencySortObjects(dictionaries, 1.11267 + CGDictionary.getDictionaryDependencies, 1.11268 + lambda d: d.identifier.name)]) 1.11269 + 1.11270 + # Do codegen for all the callbacks. 1.11271 + cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(False)) 1.11272 + for c in mainCallbacks) 1.11273 + 1.11274 + cgthings.extend(CGCallbackFunction(c, config.getDescriptorProvider(True)) 1.11275 + for c in workerCallbacks if c not in mainCallbacks) 1.11276 + 1.11277 + # Do codegen for all the descriptors 1.11278 + cgthings.extend([CGDescriptor(x) for x in descriptors]) 1.11279 + 1.11280 + # Do codegen for all the callback interfaces. Skip worker callbacks. 1.11281 + cgthings.extend([CGCallbackInterface(x) for x in callbackDescriptors if 1.11282 + not x.workers]) 1.11283 + 1.11284 + # Do codegen for JS implemented classes 1.11285 + def getParentDescriptor(desc): 1.11286 + if not desc.interface.parent: 1.11287 + return set() 1.11288 + return {desc.getDescriptor(desc.interface.parent.identifier.name)} 1.11289 + for x in dependencySortObjects(jsImplemented, getParentDescriptor, 1.11290 + lambda d: d.interface.identifier.name): 1.11291 + cgthings.append(CGCallbackInterface(x)) 1.11292 + cgthings.append(CGJSImplClass(x)) 1.11293 + 1.11294 + # And make sure we have the right number of newlines at the end 1.11295 + curr = CGWrapper(CGList(cgthings, "\n\n"), post="\n\n") 1.11296 + 1.11297 + # Wrap all of that in our namespaces. 1.11298 + curr = CGNamespace.build(['mozilla', 'dom'], 1.11299 + CGWrapper(curr, pre="\n")) 1.11300 + 1.11301 + curr = CGList([CGForwardDeclarations(config, descriptors, 1.11302 + mainCallbacks, workerCallbacks, 1.11303 + dictionaries, 1.11304 + callbackDescriptors + jsImplemented), 1.11305 + curr], 1.11306 + "\n") 1.11307 + 1.11308 + # Add header includes. 1.11309 + bindingHeaders = [header 1.11310 + for header, include in bindingHeaders.iteritems() 1.11311 + if include] 1.11312 + declareIncludes = [ 1.11313 + 'mozilla/dom/BindingDeclarations.h', 1.11314 + 'mozilla/dom/Nullable.h', 1.11315 + 'mozilla/ErrorResult.h', 1.11316 + 'jspubtd.h', 1.11317 + 'js/RootingAPI.h', 1.11318 + ] 1.11319 + if jsImplemented: 1.11320 + declareIncludes.append('nsWeakReference.h') 1.11321 + 1.11322 + curr = CGHeaders(descriptors, 1.11323 + dictionaries, 1.11324 + mainCallbacks + workerCallbacks, 1.11325 + callbackDescriptors, 1.11326 + declareIncludes, 1.11327 + bindingHeaders, 1.11328 + prefix, 1.11329 + curr, 1.11330 + config, 1.11331 + jsImplemented) 1.11332 + 1.11333 + # Add include guards. 1.11334 + curr = CGIncludeGuard(prefix, curr) 1.11335 + 1.11336 + # Add the auto-generated comment. 1.11337 + curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) 1.11338 + 1.11339 + # Store the final result. 1.11340 + self.root = curr 1.11341 + 1.11342 + def declare(self): 1.11343 + return stripTrailingWhitespace(self.root.declare()) 1.11344 + 1.11345 + def define(self): 1.11346 + return stripTrailingWhitespace(self.root.define()) 1.11347 + 1.11348 + def deps(self): 1.11349 + return self.root.deps() 1.11350 + 1.11351 + 1.11352 +class CGNativeMember(ClassMethod): 1.11353 + def __init__(self, descriptorProvider, member, name, signature, extendedAttrs, 1.11354 + breakAfter=True, passJSBitsAsNeeded=True, visibility="public", 1.11355 + jsObjectsArePtr=False, variadicIsSequence=False): 1.11356 + """ 1.11357 + If jsObjectsArePtr is true, typed arrays and "object" will be 1.11358 + passed as JSObject*. 1.11359 + 1.11360 + If passJSBitsAsNeeded is false, we don't automatically pass in a 1.11361 + JSContext* or a JSObject* based on the return and argument types. We 1.11362 + can still pass it based on 'implicitJSContext' annotations. 1.11363 + """ 1.11364 + self.descriptorProvider = descriptorProvider 1.11365 + self.member = member 1.11366 + self.extendedAttrs = extendedAttrs 1.11367 + self.resultAlreadyAddRefed = isResultAlreadyAddRefed(self.extendedAttrs) 1.11368 + self.passJSBitsAsNeeded = passJSBitsAsNeeded 1.11369 + self.jsObjectsArePtr = jsObjectsArePtr 1.11370 + self.variadicIsSequence = variadicIsSequence 1.11371 + breakAfterSelf = "\n" if breakAfter else "" 1.11372 + ClassMethod.__init__(self, name, 1.11373 + self.getReturnType(signature[0], False), 1.11374 + self.getArgs(signature[0], signature[1]), 1.11375 + static=member.isStatic(), 1.11376 + # Mark our getters, which are attrs that 1.11377 + # have a non-void return type, as const. 1.11378 + const=(not member.isStatic() and member.isAttr() and 1.11379 + not signature[0].isVoid()), 1.11380 + breakAfterReturnDecl=" ", 1.11381 + breakAfterSelf=breakAfterSelf, 1.11382 + visibility=visibility) 1.11383 + 1.11384 + def getReturnType(self, type, isMember): 1.11385 + return self.getRetvalInfo(type, isMember)[0] 1.11386 + 1.11387 + def getRetvalInfo(self, type, isMember): 1.11388 + """ 1.11389 + Returns a tuple: 1.11390 + 1.11391 + The first element is the type declaration for the retval 1.11392 + 1.11393 + The second element is a default value that can be used on error returns. 1.11394 + For cases whose behavior depends on isMember, the second element will be 1.11395 + None if isMember is true. 1.11396 + 1.11397 + The third element is a template for actually returning a value stored in 1.11398 + "${declName}" and "${holderName}". This means actually returning it if 1.11399 + we're not outparam, else assigning to the "retval" outparam. If 1.11400 + isMember is true, this can be None, since in that case the caller will 1.11401 + never examine this value. 1.11402 + """ 1.11403 + if type.isVoid(): 1.11404 + return "void", "", "" 1.11405 + if type.isPrimitive() and type.tag() in builtinNames: 1.11406 + result = CGGeneric(builtinNames[type.tag()]) 1.11407 + defaultReturnArg = "0" 1.11408 + if type.nullable(): 1.11409 + result = CGTemplatedType("Nullable", result) 1.11410 + defaultReturnArg = "" 1.11411 + return (result.define(), 1.11412 + "%s(%s)" % (result.define(), defaultReturnArg), 1.11413 + "return ${declName};\n") 1.11414 + if type.isDOMString(): 1.11415 + if isMember: 1.11416 + # No need for a third element in the isMember case 1.11417 + return "nsString", None, None 1.11418 + # Outparam 1.11419 + return "void", "", "aRetVal = ${declName};\n" 1.11420 + if type.isByteString(): 1.11421 + if isMember: 1.11422 + # No need for a third element in the isMember case 1.11423 + return "nsCString", None, None 1.11424 + # Outparam 1.11425 + return "void", "", "aRetVal = ${declName};\n" 1.11426 + if type.isEnum(): 1.11427 + enumName = type.unroll().inner.identifier.name 1.11428 + if type.nullable(): 1.11429 + enumName = CGTemplatedType("Nullable", 1.11430 + CGGeneric(enumName)).define() 1.11431 + defaultValue = "%s()" % enumName 1.11432 + else: 1.11433 + defaultValue = "%s(0)" % enumName 1.11434 + return enumName, defaultValue, "return ${declName};\n" 1.11435 + if type.isGeckoInterface(): 1.11436 + iface = type.unroll().inner 1.11437 + result = CGGeneric(self.descriptorProvider.getDescriptor( 1.11438 + iface.identifier.name).prettyNativeType) 1.11439 + if self.resultAlreadyAddRefed: 1.11440 + if isMember: 1.11441 + holder = "nsRefPtr" 1.11442 + else: 1.11443 + holder = "already_AddRefed" 1.11444 + if memberReturnsNewObject(self.member): 1.11445 + warning = "" 1.11446 + else: 1.11447 + warning = "// Mark this as resultNotAddRefed to return raw pointers\n" 1.11448 + result = CGWrapper(result, 1.11449 + pre=("%s%s<" % (warning, holder)), 1.11450 + post=">") 1.11451 + else: 1.11452 + result = CGWrapper(result, post="*") 1.11453 + # Since we always force an owning type for callback return values, 1.11454 + # our ${declName} is an OwningNonNull or nsRefPtr. So we can just 1.11455 + # .forget() to get our already_AddRefed. 1.11456 + return result.define(), "nullptr", "return ${declName}.forget();\n" 1.11457 + if type.isCallback(): 1.11458 + return ("already_AddRefed<%s>" % type.unroll().identifier.name, 1.11459 + "nullptr", "return ${declName}.forget();\n") 1.11460 + if type.isAny(): 1.11461 + if isMember: 1.11462 + # No need for a third element in the isMember case 1.11463 + return "JS::Value", None, None 1.11464 + # Outparam 1.11465 + return "void", "", "aRetVal.set(${declName});\n" 1.11466 + 1.11467 + if type.isObject(): 1.11468 + if isMember: 1.11469 + # No need for a third element in the isMember case 1.11470 + return "JSObject*", None, None 1.11471 + return "void", "", "aRetVal.set(${declName});\n" 1.11472 + if type.isSpiderMonkeyInterface(): 1.11473 + if isMember: 1.11474 + # No need for a third element in the isMember case 1.11475 + return "JSObject*", None, None 1.11476 + if type.nullable(): 1.11477 + returnCode = "${declName}.IsNull() ? nullptr : ${declName}.Value().Obj();\n" 1.11478 + else: 1.11479 + returnCode = "${declName}.Obj();\n" 1.11480 + return "void", "", "aRetVal.set(%s);\n" % returnCode 1.11481 + if type.isSequence(): 1.11482 + # If we want to handle sequence-of-sequences return values, we're 1.11483 + # going to need to fix example codegen to not produce nsTArray<void> 1.11484 + # for the relevant argument... 1.11485 + assert not isMember 1.11486 + # Outparam. 1.11487 + if type.nullable(): 1.11488 + returnCode = dedent(""" 1.11489 + if (${declName}.IsNull()) { 1.11490 + aRetVal.SetNull(); 1.11491 + } else { 1.11492 + aRetVal.SetValue().SwapElements(${declName}.Value()); 1.11493 + } 1.11494 + """) 1.11495 + else: 1.11496 + returnCode = "aRetVal.SwapElements(${declName});\n" 1.11497 + return "void", "", returnCode 1.11498 + if type.isMozMap(): 1.11499 + # If we want to handle MozMap-of-MozMap return values, we're 1.11500 + # going to need to fix example codegen to not produce MozMap<void> 1.11501 + # for the relevant argument... 1.11502 + assert not isMember 1.11503 + # In this case we convert directly into our outparam to start with 1.11504 + return "void", "", "" 1.11505 + if type.isDate(): 1.11506 + result = CGGeneric("Date") 1.11507 + if type.nullable(): 1.11508 + result = CGTemplatedType("Nullable", result) 1.11509 + return (result.define(), "%s()" % result.define(), 1.11510 + "return ${declName};\n") 1.11511 + if type.isDictionary(): 1.11512 + if isMember: 1.11513 + # Only the first member of the tuple matters here, but return 1.11514 + # bogus values for the others in case someone decides to use 1.11515 + # them. 1.11516 + return CGDictionary.makeDictionaryName(type.inner), None, None 1.11517 + # In this case we convert directly into our outparam to start with 1.11518 + return "void", "", "" 1.11519 + if type.isUnion(): 1.11520 + if isMember: 1.11521 + # Only the first member of the tuple matters here, but return 1.11522 + # bogus values for the others in case someone decides to use 1.11523 + # them. 1.11524 + return CGUnionStruct.unionTypeDecl(type, True), None, None 1.11525 + # In this case we convert directly into our outparam to start with 1.11526 + return "void", "", "" 1.11527 + 1.11528 + raise TypeError("Don't know how to declare return value for %s" % 1.11529 + type) 1.11530 + 1.11531 + def getArgs(self, returnType, argList): 1.11532 + args = [self.getArg(arg) for arg in argList] 1.11533 + # Now the outparams 1.11534 + if returnType.isDOMString(): 1.11535 + args.append(Argument("nsString&", "aRetVal")) 1.11536 + elif returnType.isByteString(): 1.11537 + args.append(Argument("nsCString&", "aRetVal")) 1.11538 + elif returnType.isSequence(): 1.11539 + nullable = returnType.nullable() 1.11540 + if nullable: 1.11541 + returnType = returnType.inner 1.11542 + # And now the actual underlying type 1.11543 + elementDecl = self.getReturnType(returnType.inner, True) 1.11544 + type = CGTemplatedType("nsTArray", CGGeneric(elementDecl)) 1.11545 + if nullable: 1.11546 + type = CGTemplatedType("Nullable", type) 1.11547 + args.append(Argument("%s&" % type.define(), "aRetVal")) 1.11548 + elif returnType.isMozMap(): 1.11549 + nullable = returnType.nullable() 1.11550 + if nullable: 1.11551 + returnType = returnType.inner 1.11552 + # And now the actual underlying type 1.11553 + elementDecl = self.getReturnType(returnType.inner, True) 1.11554 + type = CGTemplatedType("MozMap", CGGeneric(elementDecl)) 1.11555 + if nullable: 1.11556 + type = CGTemplatedType("Nullable", type) 1.11557 + args.append(Argument("%s&" % type.define(), "aRetVal")) 1.11558 + elif returnType.isDictionary(): 1.11559 + nullable = returnType.nullable() 1.11560 + if nullable: 1.11561 + returnType = returnType.inner 1.11562 + dictType = CGGeneric(CGDictionary.makeDictionaryName(returnType.inner)) 1.11563 + if nullable: 1.11564 + dictType = CGTemplatedType("Nullable", dictType) 1.11565 + args.append(Argument("%s&" % dictType.define(), "aRetVal")) 1.11566 + elif returnType.isUnion(): 1.11567 + args.append(Argument("%s&" % 1.11568 + CGUnionStruct.unionTypeDecl(returnType, True), 1.11569 + "aRetVal")) 1.11570 + elif returnType.isAny(): 1.11571 + args.append(Argument("JS::MutableHandle<JS::Value>", "aRetVal")) 1.11572 + elif returnType.isObject() or returnType.isSpiderMonkeyInterface(): 1.11573 + args.append(Argument("JS::MutableHandle<JSObject*>", "aRetVal")) 1.11574 + 1.11575 + # And the ErrorResult 1.11576 + if 'infallible' not in self.extendedAttrs: 1.11577 + # Use aRv so it won't conflict with local vars named "rv" 1.11578 + args.append(Argument("ErrorResult&", "aRv")) 1.11579 + # The legacycaller thisval 1.11580 + if self.member.isMethod() and self.member.isLegacycaller(): 1.11581 + # If it has an identifier, we can't deal with it yet 1.11582 + assert self.member.isIdentifierLess() 1.11583 + args.insert(0, Argument("JS::Value", "aThisVal")) 1.11584 + # And jscontext bits. 1.11585 + if needCx(returnType, argList, self.extendedAttrs, 1.11586 + self.passJSBitsAsNeeded): 1.11587 + args.insert(0, Argument("JSContext*", "cx")) 1.11588 + if needScopeObject(returnType, argList, self.extendedAttrs, 1.11589 + self.descriptorProvider.wrapperCache, 1.11590 + self.passJSBitsAsNeeded, 1.11591 + self.member.getExtendedAttribute("StoreInSlot")): 1.11592 + args.insert(1, Argument("JS::Handle<JSObject*>", "obj")) 1.11593 + # And if we're static, a global 1.11594 + if self.member.isStatic(): 1.11595 + args.insert(0, Argument("const GlobalObject&", "global")) 1.11596 + return args 1.11597 + 1.11598 + def doGetArgType(self, type, optional, isMember): 1.11599 + """ 1.11600 + The main work of getArgType. Returns a string type decl, whether this 1.11601 + is a const ref, as well as whether the type should be wrapped in 1.11602 + Nullable as needed. 1.11603 + 1.11604 + isMember can be false or one of the strings "Sequence", "Variadic", 1.11605 + "MozMap" 1.11606 + """ 1.11607 + if type.isArray(): 1.11608 + raise TypeError("Can't handle array arguments yet") 1.11609 + 1.11610 + if type.isSequence(): 1.11611 + nullable = type.nullable() 1.11612 + if nullable: 1.11613 + type = type.inner 1.11614 + elementType = type.inner 1.11615 + argType = self.getArgType(elementType, False, "Sequence")[0] 1.11616 + decl = CGTemplatedType("Sequence", argType) 1.11617 + return decl.define(), True, True 1.11618 + 1.11619 + if type.isMozMap(): 1.11620 + nullable = type.nullable() 1.11621 + if nullable: 1.11622 + type = type.inner 1.11623 + elementType = type.inner 1.11624 + argType = self.getArgType(elementType, False, "MozMap")[0] 1.11625 + decl = CGTemplatedType("MozMap", argType) 1.11626 + return decl.define(), True, True 1.11627 + 1.11628 + if type.isUnion(): 1.11629 + # unionTypeDecl will handle nullable types, so return False for 1.11630 + # auto-wrapping in Nullable 1.11631 + return CGUnionStruct.unionTypeDecl(type, isMember), True, False 1.11632 + 1.11633 + if type.isGeckoInterface() and not type.isCallbackInterface(): 1.11634 + iface = type.unroll().inner 1.11635 + argIsPointer = type.nullable() or iface.isExternal() 1.11636 + forceOwningType = iface.isCallback() or isMember 1.11637 + if argIsPointer: 1.11638 + if (optional or isMember) and forceOwningType: 1.11639 + typeDecl = "nsRefPtr<%s>" 1.11640 + else: 1.11641 + typeDecl = "%s*" 1.11642 + else: 1.11643 + if optional or isMember: 1.11644 + if forceOwningType: 1.11645 + typeDecl = "OwningNonNull<%s>" 1.11646 + else: 1.11647 + typeDecl = "NonNull<%s>" 1.11648 + else: 1.11649 + typeDecl = "%s&" 1.11650 + return ((typeDecl % 1.11651 + self.descriptorProvider.getDescriptor(iface.identifier.name).prettyNativeType), 1.11652 + False, False) 1.11653 + 1.11654 + if type.isSpiderMonkeyInterface(): 1.11655 + if self.jsObjectsArePtr: 1.11656 + return "JSObject*", False, False 1.11657 + 1.11658 + return type.name, True, True 1.11659 + 1.11660 + if type.isDOMString(): 1.11661 + if isMember: 1.11662 + declType = "nsString" 1.11663 + else: 1.11664 + declType = "nsAString" 1.11665 + return declType, True, False 1.11666 + 1.11667 + if type.isByteString(): 1.11668 + declType = "nsCString" 1.11669 + return declType, True, False 1.11670 + 1.11671 + if type.isEnum(): 1.11672 + return type.unroll().inner.identifier.name, False, True 1.11673 + 1.11674 + if type.isCallback() or type.isCallbackInterface(): 1.11675 + forceOwningType = optional or isMember 1.11676 + if type.nullable(): 1.11677 + if forceOwningType: 1.11678 + declType = "nsRefPtr<%s>" 1.11679 + else: 1.11680 + declType = "%s*" 1.11681 + else: 1.11682 + if forceOwningType: 1.11683 + declType = "OwningNonNull<%s>" 1.11684 + else: 1.11685 + declType = "%s&" 1.11686 + if type.isCallback(): 1.11687 + name = type.unroll().identifier.name 1.11688 + else: 1.11689 + name = type.unroll().inner.identifier.name 1.11690 + return declType % name, False, False 1.11691 + 1.11692 + if type.isAny(): 1.11693 + # Don't do the rooting stuff for variadics for now 1.11694 + if isMember: 1.11695 + declType = "JS::Value" 1.11696 + else: 1.11697 + declType = "JS::Handle<JS::Value>" 1.11698 + return declType, False, False 1.11699 + 1.11700 + if type.isObject(): 1.11701 + if isMember: 1.11702 + declType = "JSObject*" 1.11703 + else: 1.11704 + declType = "JS::Handle<JSObject*>" 1.11705 + return declType, False, False 1.11706 + 1.11707 + if type.isDictionary(): 1.11708 + typeName = CGDictionary.makeDictionaryName(type.inner) 1.11709 + return typeName, True, True 1.11710 + 1.11711 + if type.isDate(): 1.11712 + return "Date", False, True 1.11713 + 1.11714 + assert type.isPrimitive() 1.11715 + 1.11716 + return builtinNames[type.tag()], False, True 1.11717 + 1.11718 + def getArgType(self, type, optional, isMember): 1.11719 + """ 1.11720 + Get the type of an argument declaration. Returns the type CGThing, and 1.11721 + whether this should be a const ref. 1.11722 + 1.11723 + isMember can be False, "Sequence", or "Variadic" 1.11724 + """ 1.11725 + decl, ref, handleNullable = self.doGetArgType(type, optional, isMember) 1.11726 + decl = CGGeneric(decl) 1.11727 + if handleNullable and type.nullable(): 1.11728 + decl = CGTemplatedType("Nullable", decl) 1.11729 + ref = True 1.11730 + if isMember == "Variadic": 1.11731 + arrayType = "Sequence" if self.variadicIsSequence else "nsTArray" 1.11732 + decl = CGTemplatedType(arrayType, decl) 1.11733 + ref = True 1.11734 + elif optional: 1.11735 + # Note: All variadic args claim to be optional, but we can just use 1.11736 + # empty arrays to represent them not being present. 1.11737 + decl = CGTemplatedType("Optional", decl) 1.11738 + ref = True 1.11739 + return (decl, ref) 1.11740 + 1.11741 + def getArg(self, arg): 1.11742 + """ 1.11743 + Get the full argument declaration for an argument 1.11744 + """ 1.11745 + decl, ref = self.getArgType(arg.type, 1.11746 + arg.optional and not arg.defaultValue, 1.11747 + "Variadic" if arg.variadic else False) 1.11748 + if ref: 1.11749 + decl = CGWrapper(decl, pre="const ", post="&") 1.11750 + 1.11751 + return Argument(decl.define(), arg.identifier.name) 1.11752 + 1.11753 + 1.11754 +class CGExampleMethod(CGNativeMember): 1.11755 + def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True): 1.11756 + CGNativeMember.__init__(self, descriptor, method, 1.11757 + CGSpecializedMethod.makeNativeName(descriptor, 1.11758 + method), 1.11759 + signature, 1.11760 + descriptor.getExtendedAttributes(method), 1.11761 + breakAfter=breakAfter, 1.11762 + variadicIsSequence=True) 1.11763 + 1.11764 + def define(self, cgClass): 1.11765 + return '' 1.11766 + 1.11767 + 1.11768 +class CGExampleGetter(CGNativeMember): 1.11769 + def __init__(self, descriptor, attr): 1.11770 + CGNativeMember.__init__(self, descriptor, attr, 1.11771 + CGSpecializedGetter.makeNativeName(descriptor, 1.11772 + attr), 1.11773 + (attr.type, []), 1.11774 + descriptor.getExtendedAttributes(attr, 1.11775 + getter=True)) 1.11776 + 1.11777 + def define(self, cgClass): 1.11778 + return '' 1.11779 + 1.11780 + 1.11781 +class CGExampleSetter(CGNativeMember): 1.11782 + def __init__(self, descriptor, attr): 1.11783 + CGNativeMember.__init__(self, descriptor, attr, 1.11784 + CGSpecializedSetter.makeNativeName(descriptor, 1.11785 + attr), 1.11786 + (BuiltinTypes[IDLBuiltinType.Types.void], 1.11787 + [FakeArgument(attr.type, attr)]), 1.11788 + descriptor.getExtendedAttributes(attr, 1.11789 + setter=True)) 1.11790 + 1.11791 + def define(self, cgClass): 1.11792 + return '' 1.11793 + 1.11794 + 1.11795 +class CGBindingImplClass(CGClass): 1.11796 + """ 1.11797 + Common codegen for generating a C++ implementation of a WebIDL interface 1.11798 + """ 1.11799 + def __init__(self, descriptor, cgMethod, cgGetter, cgSetter, wantGetParent=True): 1.11800 + """ 1.11801 + cgMethod, cgGetter and cgSetter are classes used to codegen methods, 1.11802 + getters and setters. 1.11803 + """ 1.11804 + self.descriptor = descriptor 1.11805 + self._deps = descriptor.interface.getDeps() 1.11806 + 1.11807 + iface = descriptor.interface 1.11808 + 1.11809 + self.methodDecls = [] 1.11810 + 1.11811 + def appendMethod(m, isConstructor=False): 1.11812 + sigs = m.signatures() 1.11813 + for s in sigs[:-1]: 1.11814 + # Don't put a blank line after overloads, until we 1.11815 + # get to the last one. 1.11816 + self.methodDecls.append(cgMethod(descriptor, m, s, 1.11817 + isConstructor, 1.11818 + breakAfter=False)) 1.11819 + self.methodDecls.append(cgMethod(descriptor, m, sigs[-1], 1.11820 + isConstructor)) 1.11821 + 1.11822 + if iface.ctor(): 1.11823 + appendMethod(iface.ctor(), isConstructor=True) 1.11824 + for n in iface.namedConstructors: 1.11825 + appendMethod(n, isConstructor=True) 1.11826 + for m in iface.members: 1.11827 + if m.isMethod(): 1.11828 + if m.isIdentifierLess(): 1.11829 + continue 1.11830 + appendMethod(m) 1.11831 + elif m.isAttr(): 1.11832 + self.methodDecls.append(cgGetter(descriptor, m)) 1.11833 + if not m.readonly: 1.11834 + self.methodDecls.append(cgSetter(descriptor, m)) 1.11835 + 1.11836 + # Now do the special operations 1.11837 + def appendSpecialOperation(name, op): 1.11838 + if op is None: 1.11839 + return 1.11840 + if name == "IndexedCreator" or name == "NamedCreator": 1.11841 + # These are identical to the setters 1.11842 + return 1.11843 + assert len(op.signatures()) == 1 1.11844 + returnType, args = op.signatures()[0] 1.11845 + # Make a copy of the args, since we plan to modify them. 1.11846 + args = list(args) 1.11847 + if op.isGetter() or op.isDeleter(): 1.11848 + # This is a total hack. The '&' belongs with the 1.11849 + # type, not the name! But it works, and is simpler 1.11850 + # than trying to somehow make this pretty. 1.11851 + args.append(FakeArgument(BuiltinTypes[IDLBuiltinType.Types.boolean], 1.11852 + op, name="&found")) 1.11853 + if name == "Stringifier": 1.11854 + if op.isIdentifierLess(): 1.11855 + # XXXbz I wish we were consistent about our renaming here. 1.11856 + name = "Stringify" 1.11857 + else: 1.11858 + # We already added this method 1.11859 + return 1.11860 + if name == "LegacyCaller": 1.11861 + if op.isIdentifierLess(): 1.11862 + # XXXbz I wish we were consistent about our renaming here. 1.11863 + name = "LegacyCall" 1.11864 + else: 1.11865 + # We already added this method 1.11866 + return 1.11867 + if name == "Jsonifier": 1.11868 + # We already added this method 1.11869 + return 1.11870 + self.methodDecls.append( 1.11871 + CGNativeMember(descriptor, op, 1.11872 + name, 1.11873 + (returnType, args), 1.11874 + descriptor.getExtendedAttributes(op))) 1.11875 + # Sort things by name so we get stable ordering in the output. 1.11876 + ops = descriptor.operations.items() 1.11877 + ops.sort(key=lambda x: x[0]) 1.11878 + for name, op in ops: 1.11879 + appendSpecialOperation(name, op) 1.11880 + # If we support indexed properties, then we need a Length() 1.11881 + # method so we know which indices are supported. 1.11882 + if descriptor.supportsIndexedProperties(): 1.11883 + # But we don't need it if we already have an infallible 1.11884 + # "length" attribute, which we often do. 1.11885 + haveLengthAttr = any( 1.11886 + m for m in iface.members if m.isAttr() and 1.11887 + CGSpecializedGetter.makeNativeName(descriptor, m) == "Length") 1.11888 + if not haveLengthAttr: 1.11889 + self.methodDecls.append( 1.11890 + CGNativeMember(descriptor, FakeMember(), 1.11891 + "Length", 1.11892 + (BuiltinTypes[IDLBuiltinType.Types.unsigned_long], 1.11893 + []), 1.11894 + {"infallible": True})) 1.11895 + # And if we support named properties we need to be able to 1.11896 + # enumerate the supported names and test whether they're enumerable. 1.11897 + if descriptor.supportsNamedProperties(): 1.11898 + self.methodDecls.append( 1.11899 + CGNativeMember( 1.11900 + descriptor, FakeMember(), 1.11901 + "GetSupportedNames", 1.11902 + (IDLSequenceType(None, 1.11903 + BuiltinTypes[IDLBuiltinType.Types.domstring]), 1.11904 + # Let's use unsigned long for the type here, though really 1.11905 + # it's just a C++ "unsigned"... 1.11906 + [FakeArgument(BuiltinTypes[IDLBuiltinType.Types.unsigned_long], 1.11907 + FakeMember(), 1.11908 + name="aFlags")]), 1.11909 + {"infallible": True})) 1.11910 + self.methodDecls.append( 1.11911 + CGNativeMember( 1.11912 + descriptor, FakeMember(), 1.11913 + "NameIsEnumerable", 1.11914 + (BuiltinTypes[IDLBuiltinType.Types.boolean], 1.11915 + [FakeArgument(BuiltinTypes[IDLBuiltinType.Types.domstring], 1.11916 + FakeMember(), 1.11917 + name="aName")]), 1.11918 + { "infallible": True })) 1.11919 + 1.11920 + wrapArgs = [Argument('JSContext*', 'aCx')] 1.11921 + self.methodDecls.insert(0, 1.11922 + ClassMethod("WrapObject", "JSObject*", 1.11923 + wrapArgs, virtual=descriptor.wrapperCache, 1.11924 + breakAfterReturnDecl=" ", 1.11925 + override=descriptor.wrapperCache, 1.11926 + body=self.getWrapObjectBody())) 1.11927 + if wantGetParent: 1.11928 + self.methodDecls.insert(0, 1.11929 + ClassMethod("GetParentObject", 1.11930 + self.getGetParentObjectReturnType(), 1.11931 + [], const=True, 1.11932 + breakAfterReturnDecl=" ", 1.11933 + body=self.getGetParentObjectBody())) 1.11934 + 1.11935 + # Invoke CGClass.__init__ in any subclasses afterwards to do the actual codegen. 1.11936 + 1.11937 + def getWrapObjectBody(self): 1.11938 + return None 1.11939 + 1.11940 + def getGetParentObjectReturnType(self): 1.11941 + return ("// TODO: return something sensible here, and change the return type\n" 1.11942 + "%s*" % self.descriptor.nativeType.split('::')[-1]) 1.11943 + 1.11944 + def getGetParentObjectBody(self): 1.11945 + return None 1.11946 + 1.11947 + def deps(self): 1.11948 + return self._deps 1.11949 + 1.11950 + 1.11951 +class CGExampleClass(CGBindingImplClass): 1.11952 + """ 1.11953 + Codegen for the actual example class implementation for this descriptor 1.11954 + """ 1.11955 + def __init__(self, descriptor): 1.11956 + CGBindingImplClass.__init__(self, descriptor, 1.11957 + CGExampleMethod, CGExampleGetter, CGExampleSetter, 1.11958 + wantGetParent=descriptor.wrapperCache) 1.11959 + 1.11960 + self.refcounted = descriptor.nativeOwnership == "refcounted" 1.11961 + 1.11962 + self.parentIface = descriptor.interface.parent 1.11963 + if self.parentIface: 1.11964 + self.parentDesc = descriptor.getDescriptor( 1.11965 + self.parentIface.identifier.name) 1.11966 + bases = [ClassBase(self.nativeLeafName(self.parentDesc))] 1.11967 + else: 1.11968 + bases = [] 1.11969 + if self.refcounted: 1.11970 + bases.append(ClassBase("nsISupports /* Change nativeOwnership in the binding configuration if you don't want this */")) 1.11971 + if descriptor.wrapperCache: 1.11972 + bases.append(ClassBase("nsWrapperCache /* Change wrapperCache in the binding configuration if you don't want this */")) 1.11973 + else: 1.11974 + bases.append(ClassBase("NonRefcountedDOMObject")) 1.11975 + 1.11976 + if self.refcounted: 1.11977 + if self.parentIface: 1.11978 + extradeclarations = ( 1.11979 + "public:\n" 1.11980 + " NS_DECL_ISUPPORTS_INHERITED\n" 1.11981 + " NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(%s, %s)\n" 1.11982 + "\n" % (self.nativeLeafName(descriptor), 1.11983 + self.nativeLeafName(self.parentDesc))) 1.11984 + else: 1.11985 + extradeclarations = ( 1.11986 + "public:\n" 1.11987 + " NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n" 1.11988 + " NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n" 1.11989 + "\n" % self.nativeLeafName(descriptor)) 1.11990 + else: 1.11991 + extradeclarations = "" 1.11992 + 1.11993 + if descriptor.interface.hasChildInterfaces(): 1.11994 + decorators = "" 1.11995 + else: 1.11996 + decorators = "MOZ_FINAL" 1.11997 + 1.11998 + CGClass.__init__(self, self.nativeLeafName(descriptor), 1.11999 + bases=bases, 1.12000 + constructors=[ClassConstructor([], 1.12001 + visibility="public")], 1.12002 + destructor=ClassDestructor(visibility="public"), 1.12003 + methods=self.methodDecls, 1.12004 + decorators=decorators, 1.12005 + extradeclarations=extradeclarations) 1.12006 + 1.12007 + def define(self): 1.12008 + # Just override CGClass and do our own thing 1.12009 + if self.descriptor.wrapperCache: 1.12010 + setDOMBinding = " SetIsDOMBinding();\n" 1.12011 + else: 1.12012 + setDOMBinding = "" 1.12013 + if self.refcounted: 1.12014 + ctordtor = dedent(""" 1.12015 + ${nativeType}::${nativeType}() 1.12016 + { 1.12017 + %s} 1.12018 + 1.12019 + ${nativeType}::~${nativeType}() 1.12020 + { 1.12021 + } 1.12022 + """) % setDOMBinding 1.12023 + else: 1.12024 + ctordtor = dedent(""" 1.12025 + ${nativeType}::${nativeType}() 1.12026 + { 1.12027 + MOZ_COUNT_CTOR(${nativeType}); 1.12028 + } 1.12029 + 1.12030 + ${nativeType}::~${nativeType}() 1.12031 + { 1.12032 + MOZ_COUNT_DTOR(${nativeType}); 1.12033 + } 1.12034 + """) 1.12035 + 1.12036 + if self.refcounted: 1.12037 + if self.parentIface: 1.12038 + ccImpl = dedent(""" 1.12039 + 1.12040 + NS_IMPL_CYCLE_COLLECTION_INHERITED_0(${nativeType}, ${parentType}) 1.12041 + NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType}) 1.12042 + NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType}) 1.12043 + NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType}) 1.12044 + NS_INTERFACE_MAP_END_INHERITING(${parentType}) 1.12045 + 1.12046 + """) 1.12047 + else: 1.12048 + ccImpl = dedent(""" 1.12049 + 1.12050 + NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(${nativeType}) 1.12051 + NS_IMPL_CYCLE_COLLECTING_ADDREF(${nativeType}) 1.12052 + NS_IMPL_CYCLE_COLLECTING_RELEASE(${nativeType}) 1.12053 + NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${nativeType}) 1.12054 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.12055 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.12056 + NS_INTERFACE_MAP_END 1.12057 + 1.12058 + """) 1.12059 + else: 1.12060 + ccImpl = "" 1.12061 + 1.12062 + classImpl = ccImpl + ctordtor + "\n" + dedent(""" 1.12063 + JSObject* 1.12064 + ${nativeType}::WrapObject(JSContext* aCx) 1.12065 + { 1.12066 + return ${ifaceName}Binding::Wrap(aCx, this); 1.12067 + } 1.12068 + 1.12069 + """) 1.12070 + return string.Template(classImpl).substitute( 1.12071 + ifaceName=self.descriptor.name, 1.12072 + nativeType=self.nativeLeafName(self.descriptor), 1.12073 + parentType=self.nativeLeafName(self.parentDesc) if self.parentIface else "") 1.12074 + 1.12075 + @staticmethod 1.12076 + def nativeLeafName(descriptor): 1.12077 + return descriptor.nativeType.split('::')[-1] 1.12078 + 1.12079 + 1.12080 +class CGExampleRoot(CGThing): 1.12081 + """ 1.12082 + Root codegen class for example implementation generation. Instantiate the 1.12083 + class and call declare or define to generate header or cpp code, 1.12084 + respectively. 1.12085 + """ 1.12086 + def __init__(self, config, interfaceName): 1.12087 + # Let's assume we're not doing workers stuff 1.12088 + descriptor = config.getDescriptor(interfaceName, False) 1.12089 + 1.12090 + self.root = CGWrapper(CGExampleClass(descriptor), 1.12091 + pre="\n", post="\n") 1.12092 + 1.12093 + self.root = CGNamespace.build(["mozilla", "dom"], self.root) 1.12094 + 1.12095 + self.root = CGList([CGClassForwardDeclare("JSContext", isStruct=True), 1.12096 + self.root], "\n") 1.12097 + 1.12098 + # Throw in our #includes 1.12099 + self.root = CGHeaders([], [], [], [], 1.12100 + ["nsWrapperCache.h", 1.12101 + "nsCycleCollectionParticipant.h", 1.12102 + "mozilla/Attributes.h", 1.12103 + "mozilla/ErrorResult.h"], 1.12104 + ["mozilla/dom/%s.h" % interfaceName, 1.12105 + ("mozilla/dom/%s" % 1.12106 + CGHeaders.getDeclarationFilename(descriptor.interface))], "", self.root) 1.12107 + 1.12108 + # And now some include guards 1.12109 + self.root = CGIncludeGuard(interfaceName, self.root) 1.12110 + 1.12111 + # And our license block comes before everything else 1.12112 + self.root = CGWrapper(self.root, pre=dedent(""" 1.12113 + /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.12114 + /* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.12115 + /* This Source Code Form is subject to the terms of the Mozilla Public 1.12116 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.12117 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.12118 + 1.12119 + """)) 1.12120 + 1.12121 + def declare(self): 1.12122 + return self.root.declare() 1.12123 + 1.12124 + def define(self): 1.12125 + return self.root.define() 1.12126 + 1.12127 + 1.12128 +def jsImplName(name): 1.12129 + return name + "JSImpl" 1.12130 + 1.12131 + 1.12132 +class CGJSImplMember(CGNativeMember): 1.12133 + """ 1.12134 + Base class for generating code for the members of the implementation class 1.12135 + for a JS-implemented WebIDL interface. 1.12136 + """ 1.12137 + def __init__(self, descriptorProvider, member, name, signature, 1.12138 + extendedAttrs, breakAfter=True, passJSBitsAsNeeded=True, 1.12139 + visibility="public", jsObjectsArePtr=False, 1.12140 + variadicIsSequence=False): 1.12141 + CGNativeMember.__init__(self, descriptorProvider, member, name, 1.12142 + signature, extendedAttrs, breakAfter=breakAfter, 1.12143 + passJSBitsAsNeeded=passJSBitsAsNeeded, 1.12144 + visibility=visibility, 1.12145 + jsObjectsArePtr=jsObjectsArePtr, 1.12146 + variadicIsSequence=variadicIsSequence) 1.12147 + self.body = self.getImpl() 1.12148 + 1.12149 + def getArgs(self, returnType, argList): 1.12150 + args = CGNativeMember.getArgs(self, returnType, argList) 1.12151 + args.append(Argument("JSCompartment*", "aCompartment", "nullptr")) 1.12152 + return args 1.12153 + 1.12154 + 1.12155 +class CGJSImplMethod(CGJSImplMember): 1.12156 + """ 1.12157 + Class for generating code for the methods for a JS-implemented WebIDL 1.12158 + interface. 1.12159 + """ 1.12160 + def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True): 1.12161 + self.signature = signature 1.12162 + self.descriptor = descriptor 1.12163 + self.isConstructor = isConstructor 1.12164 + CGJSImplMember.__init__(self, descriptor, method, 1.12165 + CGSpecializedMethod.makeNativeName(descriptor, 1.12166 + method), 1.12167 + signature, 1.12168 + descriptor.getExtendedAttributes(method), 1.12169 + breakAfter=breakAfter, 1.12170 + variadicIsSequence=True, 1.12171 + passJSBitsAsNeeded=False) 1.12172 + 1.12173 + def getArgs(self, returnType, argList): 1.12174 + if self.isConstructor: 1.12175 + # Skip the JSCompartment bits for constructors; it's handled 1.12176 + # manually in getImpl. 1.12177 + return CGNativeMember.getArgs(self, returnType, argList) 1.12178 + return CGJSImplMember.getArgs(self, returnType, argList) 1.12179 + 1.12180 + def getImpl(self): 1.12181 + args = self.getArgs(self.signature[0], self.signature[1]) 1.12182 + if not self.isConstructor: 1.12183 + return 'return mImpl->%s(%s);\n' % (self.name, ", ".join(arg.name for arg in args)) 1.12184 + 1.12185 + assert self.descriptor.interface.isJSImplemented() 1.12186 + if self.name != 'Constructor': 1.12187 + raise TypeError("Named constructors are not supported for JS implemented WebIDL. See bug 851287.") 1.12188 + if len(self.signature[1]) != 0: 1.12189 + # The first two arguments to the constructor implementation are not 1.12190 + # arguments to the WebIDL constructor, so don't pass them to __Init() 1.12191 + assert args[0].argType == 'const GlobalObject&' 1.12192 + assert args[1].argType == 'JSContext*' 1.12193 + constructorArgs = [arg.name for arg in args[2:]] 1.12194 + constructorArgs.append("js::GetObjectCompartment(scopeObj)") 1.12195 + initCall = fill( 1.12196 + """ 1.12197 + // Wrap the object before calling __Init so that __DOM_IMPL__ is available. 1.12198 + nsCOMPtr<nsIGlobalObject> globalHolder = do_QueryInterface(window); 1.12199 + JS::Rooted<JSObject*> scopeObj(cx, globalHolder->GetGlobalJSObject()); 1.12200 + MOZ_ASSERT(js::IsObjectInContextCompartment(scopeObj, cx)); 1.12201 + JS::Rooted<JS::Value> wrappedVal(cx); 1.12202 + if (!WrapNewBindingObject(cx, impl, &wrappedVal)) { 1.12203 + //XXX Assertion disabled for now, see bug 991271. 1.12204 + MOZ_ASSERT(true || JS_IsExceptionPending(cx)); 1.12205 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.12206 + return nullptr; 1.12207 + } 1.12208 + // Initialize the object with the constructor arguments. 1.12209 + impl->mImpl->__Init(${args}); 1.12210 + if (aRv.Failed()) { 1.12211 + return nullptr; 1.12212 + } 1.12213 + """, 1.12214 + args=", ".join(constructorArgs)) 1.12215 + else: 1.12216 + initCall = "" 1.12217 + return genConstructorBody(self.descriptor, initCall) 1.12218 + 1.12219 + 1.12220 +def genConstructorBody(descriptor, initCall=""): 1.12221 + return fill( 1.12222 + """ 1.12223 + JS::Rooted<JSObject*> jsImplObj(cx); 1.12224 + nsCOMPtr<nsPIDOMWindow> window = 1.12225 + ConstructJSImplementation(cx, "${contractId}", global, &jsImplObj, aRv); 1.12226 + if (aRv.Failed()) { 1.12227 + return nullptr; 1.12228 + } 1.12229 + // Build the C++ implementation. 1.12230 + nsRefPtr<${implClass}> impl = new ${implClass}(jsImplObj, window); 1.12231 + $*{initCall} 1.12232 + return impl.forget(); 1.12233 + """, 1.12234 + contractId=descriptor.interface.getJSImplementation(), 1.12235 + implClass=descriptor.name, 1.12236 + initCall=initCall) 1.12237 + 1.12238 + 1.12239 +# We're always fallible 1.12240 +def callbackGetterName(attr, descriptor): 1.12241 + return "Get" + MakeNativeName( 1.12242 + descriptor.binaryNames.get(attr.identifier.name, attr.identifier.name)) 1.12243 + 1.12244 + 1.12245 +def callbackSetterName(attr, descriptor): 1.12246 + return "Set" + MakeNativeName( 1.12247 + descriptor.binaryNames.get(attr.identifier.name, attr.identifier.name)) 1.12248 + 1.12249 + 1.12250 +class CGJSImplGetter(CGJSImplMember): 1.12251 + """ 1.12252 + Class for generating code for the getters of attributes for a JS-implemented 1.12253 + WebIDL interface. 1.12254 + """ 1.12255 + def __init__(self, descriptor, attr): 1.12256 + CGJSImplMember.__init__(self, descriptor, attr, 1.12257 + CGSpecializedGetter.makeNativeName(descriptor, 1.12258 + attr), 1.12259 + (attr.type, []), 1.12260 + descriptor.getExtendedAttributes(attr, 1.12261 + getter=True), 1.12262 + passJSBitsAsNeeded=False) 1.12263 + 1.12264 + def getImpl(self): 1.12265 + callbackArgs = [arg.name for arg in self.getArgs(self.member.type, [])] 1.12266 + return 'return mImpl->%s(%s);\n' % ( 1.12267 + callbackGetterName(self.member, self.descriptorProvider), 1.12268 + ", ".join(callbackArgs)) 1.12269 + 1.12270 + 1.12271 +class CGJSImplSetter(CGJSImplMember): 1.12272 + """ 1.12273 + Class for generating code for the setters of attributes for a JS-implemented 1.12274 + WebIDL interface. 1.12275 + """ 1.12276 + def __init__(self, descriptor, attr): 1.12277 + CGJSImplMember.__init__(self, descriptor, attr, 1.12278 + CGSpecializedSetter.makeNativeName(descriptor, 1.12279 + attr), 1.12280 + (BuiltinTypes[IDLBuiltinType.Types.void], 1.12281 + [FakeArgument(attr.type, attr)]), 1.12282 + descriptor.getExtendedAttributes(attr, 1.12283 + setter=True), 1.12284 + passJSBitsAsNeeded=False) 1.12285 + 1.12286 + def getImpl(self): 1.12287 + callbackArgs = [arg.name for arg in self.getArgs(BuiltinTypes[IDLBuiltinType.Types.void], 1.12288 + [FakeArgument(self.member.type, self.member)])] 1.12289 + return 'mImpl->%s(%s);\n' % ( 1.12290 + callbackSetterName(self.member, self.descriptorProvider), 1.12291 + ", ".join(callbackArgs)) 1.12292 + 1.12293 + 1.12294 +class CGJSImplClass(CGBindingImplClass): 1.12295 + def __init__(self, descriptor): 1.12296 + CGBindingImplClass.__init__(self, descriptor, CGJSImplMethod, CGJSImplGetter, CGJSImplSetter) 1.12297 + 1.12298 + if descriptor.interface.parent: 1.12299 + parentClass = descriptor.getDescriptor( 1.12300 + descriptor.interface.parent.identifier.name).jsImplParent 1.12301 + baseClasses = [ClassBase(parentClass)] 1.12302 + isupportsDecl = "NS_DECL_ISUPPORTS_INHERITED\n" 1.12303 + ccDecl = ("NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(%s, %s)\n" % 1.12304 + (descriptor.name, parentClass)) 1.12305 + constructorBody = dedent(""" 1.12306 + // Make sure we're an nsWrapperCache already 1.12307 + MOZ_ASSERT(static_cast<nsWrapperCache*>(this)); 1.12308 + // And that our ancestor has called SetIsDOMBinding() 1.12309 + MOZ_ASSERT(IsDOMBinding()); 1.12310 + """) 1.12311 + extradefinitions = fill( 1.12312 + """ 1.12313 + NS_IMPL_CYCLE_COLLECTION_INHERITED(${ifaceName}, ${parentClass}, mImpl, mParent) 1.12314 + NS_IMPL_ADDREF_INHERITED(${ifaceName}, ${parentClass}) 1.12315 + NS_IMPL_RELEASE_INHERITED(${ifaceName}, ${parentClass}) 1.12316 + NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(${ifaceName}) 1.12317 + NS_INTERFACE_MAP_END_INHERITING(${parentClass}) 1.12318 + """, 1.12319 + ifaceName=self.descriptor.name, 1.12320 + parentClass=parentClass) 1.12321 + else: 1.12322 + baseClasses = [ClassBase("nsSupportsWeakReference"), 1.12323 + ClassBase("nsWrapperCache")] 1.12324 + isupportsDecl = "NS_DECL_CYCLE_COLLECTING_ISUPPORTS\n" 1.12325 + ccDecl = ("NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(%s)\n" % 1.12326 + descriptor.name) 1.12327 + constructorBody = "SetIsDOMBinding();\n" 1.12328 + extradefinitions = fill( 1.12329 + """ 1.12330 + NS_IMPL_CYCLE_COLLECTION_CLASS(${ifaceName}) 1.12331 + NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(${ifaceName}) 1.12332 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mImpl) 1.12333 + NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent) 1.12334 + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 1.12335 + tmp->ClearWeakReferences(); 1.12336 + NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.12337 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(${ifaceName}) 1.12338 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImpl) 1.12339 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent) 1.12340 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.12341 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.12342 + NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(${ifaceName}) 1.12343 + NS_IMPL_CYCLE_COLLECTING_ADDREF(${ifaceName}) 1.12344 + NS_IMPL_CYCLE_COLLECTING_RELEASE(${ifaceName}) 1.12345 + NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(${ifaceName}) 1.12346 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.12347 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.12348 + NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) 1.12349 + NS_INTERFACE_MAP_END 1.12350 + """, 1.12351 + ifaceName=self.descriptor.name) 1.12352 + 1.12353 + extradeclarations = fill( 1.12354 + """ 1.12355 + public: 1.12356 + $*{isupportsDecl} 1.12357 + $*{ccDecl} 1.12358 + 1.12359 + private: 1.12360 + nsRefPtr<${jsImplName}> mImpl; 1.12361 + nsCOMPtr<nsISupports> mParent; 1.12362 + 1.12363 + """, 1.12364 + isupportsDecl=isupportsDecl, 1.12365 + ccDecl=ccDecl, 1.12366 + jsImplName=jsImplName(descriptor.name)) 1.12367 + 1.12368 + if descriptor.interface.hasChildInterfaces(): 1.12369 + decorators = "" 1.12370 + # We need a public virtual destructor our subclasses can use 1.12371 + destructor = ClassDestructor(virtual=True, visibility="public") 1.12372 + else: 1.12373 + decorators = "MOZ_FINAL" 1.12374 + destructor = None 1.12375 + 1.12376 + baseConstructors = [ 1.12377 + ("mImpl(new %s(aJSImplObject, /* aIncumbentGlobal = */ nullptr))" % 1.12378 + jsImplName(descriptor.name)), 1.12379 + "mParent(aParent)"] 1.12380 + parentInterface = descriptor.interface.parent 1.12381 + while parentInterface: 1.12382 + if parentInterface.isJSImplemented(): 1.12383 + baseConstructors.insert( 1.12384 + 0, "%s(aJSImplObject, aParent)" % parentClass) 1.12385 + break 1.12386 + parentInterface = parentInterface.parent 1.12387 + if not parentInterface and descriptor.interface.parent: 1.12388 + # We only have C++ ancestors, so only pass along the window 1.12389 + baseConstructors.insert(0, 1.12390 + "%s(aParent)" % parentClass) 1.12391 + 1.12392 + constructor = ClassConstructor( 1.12393 + [Argument("JS::Handle<JSObject*>", "aJSImplObject"), 1.12394 + Argument("nsPIDOMWindow*", "aParent")], 1.12395 + visibility="public", 1.12396 + baseConstructors=baseConstructors, 1.12397 + body=constructorBody) 1.12398 + 1.12399 + self.methodDecls.append( 1.12400 + ClassMethod("_Create", 1.12401 + "bool", 1.12402 + [Argument("JSContext*", "cx"), 1.12403 + Argument("unsigned", "argc"), 1.12404 + Argument("JS::Value*", "vp")], 1.12405 + static=True, 1.12406 + body=self.getCreateFromExistingBody())) 1.12407 + 1.12408 + CGClass.__init__(self, descriptor.name, 1.12409 + bases=baseClasses, 1.12410 + constructors=[constructor], 1.12411 + destructor=destructor, 1.12412 + methods=self.methodDecls, 1.12413 + decorators=decorators, 1.12414 + extradeclarations=extradeclarations, 1.12415 + extradefinitions=extradefinitions) 1.12416 + 1.12417 + def getWrapObjectBody(self): 1.12418 + return fill( 1.12419 + """ 1.12420 + JS::Rooted<JSObject*> obj(aCx, ${name}Binding::Wrap(aCx, this)); 1.12421 + if (!obj) { 1.12422 + return nullptr; 1.12423 + } 1.12424 + 1.12425 + // Now define it on our chrome object 1.12426 + JSAutoCompartment ac(aCx, mImpl->Callback()); 1.12427 + if (!JS_WrapObject(aCx, &obj)) { 1.12428 + return nullptr; 1.12429 + } 1.12430 + if (!JS_DefineProperty(aCx, mImpl->Callback(), "__DOM_IMPL__", obj, 0)) { 1.12431 + return nullptr; 1.12432 + } 1.12433 + return obj; 1.12434 + """, 1.12435 + name=self.descriptor.name) 1.12436 + 1.12437 + def getGetParentObjectReturnType(self): 1.12438 + return "nsISupports*" 1.12439 + 1.12440 + def getGetParentObjectBody(self): 1.12441 + return "return mParent;\n" 1.12442 + 1.12443 + def getCreateFromExistingBody(self): 1.12444 + # XXXbz we could try to get parts of this (e.g. the argument 1.12445 + # conversions) auto-generated by somehow creating an IDLMethod and 1.12446 + # adding it to our interface, but we'd still need to special-case the 1.12447 + # implementation slightly to have it not try to forward to the JS 1.12448 + # object... 1.12449 + return fill( 1.12450 + """ 1.12451 + JS::CallArgs args = JS::CallArgsFromVp(argc, vp); 1.12452 + if (args.length() < 2) { 1.12453 + return ThrowErrorMessage(cx, MSG_MISSING_ARGUMENTS, "${ifaceName}._create"); 1.12454 + } 1.12455 + if (!args[0].isObject()) { 1.12456 + return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 1 of ${ifaceName}._create"); 1.12457 + } 1.12458 + if (!args[1].isObject()) { 1.12459 + return ThrowErrorMessage(cx, MSG_NOT_OBJECT, "Argument 2 of ${ifaceName}._create"); 1.12460 + } 1.12461 + 1.12462 + // GlobalObject will go through wrappers as needed for us, and 1.12463 + // is simpler than the right UnwrapArg incantation. 1.12464 + GlobalObject global(cx, &args[0].toObject()); 1.12465 + if (global.Failed()) { 1.12466 + return false; 1.12467 + } 1.12468 + nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(global.GetAsSupports()); 1.12469 + if (!window) { 1.12470 + return ThrowErrorMessage(cx, MSG_DOES_NOT_IMPLEMENT_INTERFACE, "Argument 1 of ${ifaceName}._create", "Window"); 1.12471 + } 1.12472 + JS::Rooted<JSObject*> arg(cx, &args[1].toObject()); 1.12473 + nsRefPtr<${implName}> impl = new ${implName}(arg, window); 1.12474 + MOZ_ASSERT(js::IsObjectInContextCompartment(arg, cx)); 1.12475 + return WrapNewBindingObject(cx, impl, args.rval()); 1.12476 + """, 1.12477 + ifaceName=self.descriptor.interface.identifier.name, 1.12478 + implName=self.descriptor.name) 1.12479 + 1.12480 + 1.12481 +def isJSImplementedDescriptor(descriptorProvider): 1.12482 + return (isinstance(descriptorProvider, Descriptor) and 1.12483 + descriptorProvider.interface.isJSImplemented()) 1.12484 + 1.12485 + 1.12486 +class CGCallback(CGClass): 1.12487 + def __init__(self, idlObject, descriptorProvider, baseName, methods, 1.12488 + getters=[], setters=[]): 1.12489 + self.baseName = baseName 1.12490 + self._deps = idlObject.getDeps() 1.12491 + self.idlObject = idlObject 1.12492 + name = idlObject.identifier.name 1.12493 + if isJSImplementedDescriptor(descriptorProvider): 1.12494 + name = jsImplName(name) 1.12495 + # For our public methods that needThisHandling we want most of the 1.12496 + # same args and the same return type as what CallbackMember 1.12497 + # generates. So we want to take advantage of all its 1.12498 + # CGNativeMember infrastructure, but that infrastructure can't deal 1.12499 + # with templates and most especially template arguments. So just 1.12500 + # cheat and have CallbackMember compute all those things for us. 1.12501 + realMethods = [] 1.12502 + for method in methods: 1.12503 + if not method.needThisHandling: 1.12504 + realMethods.append(method) 1.12505 + else: 1.12506 + realMethods.extend(self.getMethodImpls(method)) 1.12507 + realMethods.append( 1.12508 + ClassMethod("operator==", "bool", 1.12509 + [Argument("const %s&" % name, "aOther")], 1.12510 + inline=True, bodyInHeader=True, 1.12511 + const=True, 1.12512 + body=("return %s::operator==(aOther);\n" % baseName))) 1.12513 + CGClass.__init__(self, name, 1.12514 + bases=[ClassBase(baseName)], 1.12515 + constructors=self.getConstructors(), 1.12516 + methods=realMethods+getters+setters) 1.12517 + 1.12518 + def getConstructors(self): 1.12519 + if (not self.idlObject.isInterface() and 1.12520 + not self.idlObject._treatNonObjectAsNull): 1.12521 + body = "MOZ_ASSERT(JS_ObjectIsCallable(nullptr, mCallback));\n" 1.12522 + else: 1.12523 + # Not much we can assert about it, other than not being null, and 1.12524 + # CallbackObject does that already. 1.12525 + body = "" 1.12526 + return [ClassConstructor( 1.12527 + [Argument("JS::Handle<JSObject*>", "aCallback"), 1.12528 + Argument("nsIGlobalObject*", "aIncumbentGlobal")], 1.12529 + bodyInHeader=True, 1.12530 + visibility="public", 1.12531 + explicit=True, 1.12532 + baseConstructors=[ 1.12533 + "%s(aCallback, aIncumbentGlobal)" % self.baseName, 1.12534 + ], 1.12535 + body=body)] 1.12536 + 1.12537 + def getMethodImpls(self, method): 1.12538 + assert method.needThisHandling 1.12539 + args = list(method.args) 1.12540 + # Strip out the JSContext*/JSObject* args 1.12541 + # that got added. 1.12542 + assert args[0].name == "cx" and args[0].argType == "JSContext*" 1.12543 + assert args[1].name == "aThisVal" and args[1].argType == "JS::Handle<JS::Value>" 1.12544 + args = args[2:] 1.12545 + # Record the names of all the arguments, so we can use them when we call 1.12546 + # the private method. 1.12547 + argnames = [arg.name for arg in args] 1.12548 + argnamesWithThis = ["s.GetContext()", "thisValJS"] + argnames 1.12549 + argnamesWithoutThis = ["s.GetContext()", "JS::UndefinedHandleValue"] + argnames 1.12550 + # Now that we've recorded the argnames for our call to our private 1.12551 + # method, insert our optional argument for deciding whether the 1.12552 + # CallSetup should re-throw exceptions on aRv. 1.12553 + args.append(Argument("ExceptionHandling", "aExceptionHandling", 1.12554 + "eReportExceptions")) 1.12555 + # And now insert our template argument. 1.12556 + argsWithoutThis = list(args) 1.12557 + args.insert(0, Argument("const T&", "thisObjPtr")) 1.12558 + errorReturn = method.getDefaultRetval() 1.12559 + 1.12560 + setupCall = fill( 1.12561 + """ 1.12562 + CallSetup s(this, aRv, aExceptionHandling); 1.12563 + if (!s.GetContext()) { 1.12564 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.12565 + return${errorReturn}; 1.12566 + } 1.12567 + """, 1.12568 + errorReturn=errorReturn) 1.12569 + 1.12570 + bodyWithThis = fill( 1.12571 + """ 1.12572 + $*{setupCall} 1.12573 + JS::Rooted<JSObject*> thisObjJS(s.GetContext(), 1.12574 + WrapCallThisObject(s.GetContext(), thisObjPtr)); 1.12575 + if (!thisObjJS) { 1.12576 + aRv.Throw(NS_ERROR_FAILURE); 1.12577 + return${errorReturn}; 1.12578 + } 1.12579 + JS::Rooted<JS::Value> thisValJS(s.GetContext(), 1.12580 + JS::ObjectValue(*thisObjJS)); 1.12581 + return ${methodName}(${callArgs}); 1.12582 + """, 1.12583 + setupCall=setupCall, 1.12584 + errorReturn=errorReturn, 1.12585 + methodName=method.name, 1.12586 + callArgs=", ".join(argnamesWithThis)) 1.12587 + bodyWithoutThis = fill( 1.12588 + """ 1.12589 + $*{setupCall} 1.12590 + return ${methodName}(${callArgs}); 1.12591 + """, 1.12592 + setupCall=setupCall, 1.12593 + errorReturn=errorReturn, 1.12594 + methodName=method.name, 1.12595 + callArgs=", ".join(argnamesWithoutThis)) 1.12596 + 1.12597 + return [ClassMethod(method.name, method.returnType, args, 1.12598 + bodyInHeader=True, 1.12599 + templateArgs=["typename T"], 1.12600 + body=bodyWithThis), 1.12601 + ClassMethod(method.name, method.returnType, argsWithoutThis, 1.12602 + bodyInHeader=True, 1.12603 + body=bodyWithoutThis), 1.12604 + method] 1.12605 + 1.12606 + def deps(self): 1.12607 + return self._deps 1.12608 + 1.12609 + 1.12610 +class CGCallbackFunction(CGCallback): 1.12611 + def __init__(self, callback, descriptorProvider): 1.12612 + self.callback = callback 1.12613 + CGCallback.__init__(self, callback, descriptorProvider, 1.12614 + "CallbackFunction", 1.12615 + methods=[CallCallback(callback, descriptorProvider)]) 1.12616 + 1.12617 + def getConstructors(self): 1.12618 + return CGCallback.getConstructors(self) + [ 1.12619 + ClassConstructor( 1.12620 + [Argument("CallbackFunction*", "aOther")], 1.12621 + bodyInHeader=True, 1.12622 + visibility="public", 1.12623 + explicit=True, 1.12624 + baseConstructors=["CallbackFunction(aOther)"])] 1.12625 + 1.12626 + 1.12627 +class CGCallbackInterface(CGCallback): 1.12628 + def __init__(self, descriptor): 1.12629 + iface = descriptor.interface 1.12630 + attrs = [m for m in iface.members if m.isAttr() and not m.isStatic()] 1.12631 + getters = [CallbackGetter(a, descriptor) for a in attrs] 1.12632 + setters = [CallbackSetter(a, descriptor) for a in attrs 1.12633 + if not a.readonly] 1.12634 + methods = [m for m in iface.members 1.12635 + if m.isMethod() and not m.isStatic() and not m.isIdentifierLess()] 1.12636 + methods = [CallbackOperation(m, sig, descriptor) for m in methods 1.12637 + for sig in m.signatures()] 1.12638 + if iface.isJSImplemented() and iface.ctor(): 1.12639 + sigs = descriptor.interface.ctor().signatures() 1.12640 + if len(sigs) != 1: 1.12641 + raise TypeError("We only handle one constructor. See bug 869268.") 1.12642 + methods.append(CGJSImplInitOperation(sigs[0], descriptor)) 1.12643 + CGCallback.__init__(self, iface, descriptor, "CallbackInterface", 1.12644 + methods, getters=getters, setters=setters) 1.12645 + 1.12646 + 1.12647 +class FakeMember(): 1.12648 + def __init__(self): 1.12649 + self.treatNullAs = "Default" 1.12650 + 1.12651 + def isStatic(self): 1.12652 + return False 1.12653 + 1.12654 + def isAttr(self): 1.12655 + return False 1.12656 + 1.12657 + def isMethod(self): 1.12658 + return False 1.12659 + 1.12660 + def getExtendedAttribute(self, name): 1.12661 + # Claim to be a [NewObject] so we can avoid the "mark this 1.12662 + # resultNotAddRefed" comments CGNativeMember codegen would 1.12663 + # otherwise stick in. 1.12664 + if name == "NewObject": 1.12665 + return True 1.12666 + return None 1.12667 + 1.12668 + 1.12669 +class CallbackMember(CGNativeMember): 1.12670 + def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException=False): 1.12671 + """ 1.12672 + needThisHandling is True if we need to be able to accept a specified 1.12673 + thisObj, False otherwise. 1.12674 + """ 1.12675 + assert not rethrowContentException or not needThisHandling 1.12676 + 1.12677 + self.retvalType = sig[0] 1.12678 + self.originalSig = sig 1.12679 + args = sig[1] 1.12680 + self.argCount = len(args) 1.12681 + if self.argCount > 0: 1.12682 + # Check for variadic arguments 1.12683 + lastArg = args[self.argCount-1] 1.12684 + if lastArg.variadic: 1.12685 + self.argCountStr = ("(%d - 1) + %s.Length()" % 1.12686 + (self.argCount, lastArg.identifier.name)) 1.12687 + else: 1.12688 + self.argCountStr = "%d" % self.argCount 1.12689 + self.needThisHandling = needThisHandling 1.12690 + # If needThisHandling, we generate ourselves as private and the caller 1.12691 + # will handle generating public versions that handle the "this" stuff. 1.12692 + visibility = "private" if needThisHandling else "public" 1.12693 + self.rethrowContentException = rethrowContentException 1.12694 + # We don't care, for callback codegen, whether our original member was 1.12695 + # a method or attribute or whatnot. Just always pass FakeMember() 1.12696 + # here. 1.12697 + CGNativeMember.__init__(self, descriptorProvider, FakeMember(), 1.12698 + name, (self.retvalType, args), 1.12699 + extendedAttrs={}, 1.12700 + passJSBitsAsNeeded=False, 1.12701 + visibility=visibility, 1.12702 + jsObjectsArePtr=True) 1.12703 + # We have to do all the generation of our body now, because 1.12704 + # the caller relies on us throwing if we can't manage it. 1.12705 + self.exceptionCode = ("aRv.Throw(NS_ERROR_UNEXPECTED);\n" 1.12706 + "return%s;\n" % self.getDefaultRetval()) 1.12707 + self.body = self.getImpl() 1.12708 + 1.12709 + def getImpl(self): 1.12710 + setupCall = self.getCallSetup() 1.12711 + declRval = self.getRvalDecl() 1.12712 + if self.argCount > 0: 1.12713 + argvDecl = fill( 1.12714 + """ 1.12715 + JS::AutoValueVector argv(cx); 1.12716 + if (!argv.resize(${argCount})) { 1.12717 + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 1.12718 + return${errorReturn}; 1.12719 + } 1.12720 + """, 1.12721 + argCount=self.argCountStr, 1.12722 + errorReturn=self.getDefaultRetval()) 1.12723 + else: 1.12724 + # Avoid weird 0-sized arrays 1.12725 + argvDecl = "" 1.12726 + convertArgs = self.getArgConversions() 1.12727 + doCall = self.getCall() 1.12728 + returnResult = self.getResultConversion() 1.12729 + 1.12730 + return setupCall + declRval + argvDecl + convertArgs + doCall + returnResult 1.12731 + 1.12732 + def getResultConversion(self): 1.12733 + replacements = { 1.12734 + "val": "rval", 1.12735 + "mutableVal": "&rval", 1.12736 + "holderName": "rvalHolder", 1.12737 + "declName": "rvalDecl", 1.12738 + # We actually want to pass in a null scope object here, because 1.12739 + # wrapping things into our current compartment (that of mCallback) 1.12740 + # is what we want. 1.12741 + "obj": "nullptr" 1.12742 + } 1.12743 + 1.12744 + if isJSImplementedDescriptor(self.descriptorProvider): 1.12745 + isCallbackReturnValue = "JSImpl" 1.12746 + else: 1.12747 + isCallbackReturnValue = "Callback" 1.12748 + sourceDescription = "return value of %s" % self.getPrettyName() 1.12749 + convertType = instantiateJSToNativeConversion( 1.12750 + getJSToNativeConversionInfo(self.retvalType, 1.12751 + self.descriptorProvider, 1.12752 + exceptionCode=self.exceptionCode, 1.12753 + isCallbackReturnValue=isCallbackReturnValue, 1.12754 + sourceDescription=sourceDescription), 1.12755 + replacements) 1.12756 + assignRetval = string.Template( 1.12757 + self.getRetvalInfo(self.retvalType, 1.12758 + False)[2]).substitute(replacements) 1.12759 + type = convertType.define() 1.12760 + if type == "": 1.12761 + type = "\n" # BOGUS extra blank line 1.12762 + if assignRetval == "": 1.12763 + assignRetval = "\n" # BOGUS extra blank line 1.12764 + return type + assignRetval 1.12765 + 1.12766 + def getArgConversions(self): 1.12767 + # Just reget the arglist from self.originalSig, because our superclasses 1.12768 + # just have way to many members they like to clobber, so I can't find a 1.12769 + # safe member name to store it in. 1.12770 + argConversions = [self.getArgConversion(i, arg) 1.12771 + for i, arg in enumerate(self.originalSig[1])] 1.12772 + if not argConversions: 1.12773 + return "\n\n" # BOGUS extra blank line 1.12774 + 1.12775 + # Do them back to front, so our argc modifications will work 1.12776 + # correctly, because we examine trailing arguments first. 1.12777 + argConversions.reverse() 1.12778 + # Wrap each one in a scope so that any locals it has don't leak out, and 1.12779 + # also so that we can just "break;" for our successCode. 1.12780 + argConversions = [CGWrapper(CGIndenter(CGGeneric(c)), 1.12781 + pre="do {\n", 1.12782 + post="} while (0);\n") 1.12783 + for c in argConversions] 1.12784 + if self.argCount > 0: 1.12785 + argConversions.insert(0, self.getArgcDecl()) 1.12786 + # And slap them together. 1.12787 + return CGList(argConversions, "\n").define() + "\n" 1.12788 + 1.12789 + def getArgConversion(self, i, arg): 1.12790 + argval = arg.identifier.name 1.12791 + 1.12792 + if arg.variadic: 1.12793 + argval = argval + "[idx]" 1.12794 + jsvalIndex = "%d + idx" % i 1.12795 + else: 1.12796 + jsvalIndex = "%d" % i 1.12797 + if arg.optional and not arg.defaultValue: 1.12798 + argval += ".Value()" 1.12799 + if arg.type.isDOMString(): 1.12800 + # XPConnect string-to-JS conversion wants to mutate the string. So 1.12801 + # let's give it a string it can mutate 1.12802 + # XXXbz if we try to do a sequence of strings, this will kinda fail. 1.12803 + result = "mutableStr" 1.12804 + prepend = "nsString mutableStr(%s);\n" % argval 1.12805 + else: 1.12806 + result = argval 1.12807 + prepend = "" 1.12808 + 1.12809 + try: 1.12810 + conversion = prepend + wrapForType( 1.12811 + arg.type, self.descriptorProvider, 1.12812 + { 1.12813 + 'result': result, 1.12814 + 'successCode': "continue;\n" if arg.variadic else "break;\n", 1.12815 + 'jsvalRef': "argv.handleAt(%s)" % jsvalIndex, 1.12816 + 'jsvalHandle': "argv.handleAt(%s)" % jsvalIndex, 1.12817 + # XXXbz we don't have anything better to use for 'obj', 1.12818 + # really... It's OK to use CallbackPreserveColor because 1.12819 + # CallSetup already handled the unmark-gray bits for us. 1.12820 + 'obj': 'CallbackPreserveColor()', 1.12821 + 'returnsNewObject': False, 1.12822 + 'exceptionCode': self.exceptionCode 1.12823 + }) 1.12824 + except MethodNotNewObjectError as err: 1.12825 + raise TypeError("%s being passed as an argument to %s but is not " 1.12826 + "wrapper cached, so can't be reliably converted to " 1.12827 + "a JS object." % 1.12828 + (err.typename, self.getPrettyName())) 1.12829 + if arg.variadic: 1.12830 + conversion = fill( 1.12831 + """ 1.12832 + for (uint32_t idx = 0; idx < ${arg}.Length(); ++idx) { 1.12833 + $*{conversion} 1.12834 + } 1.12835 + break; 1.12836 + """, 1.12837 + arg=arg.identifier.name, 1.12838 + conversion=conversion) 1.12839 + elif arg.optional and not arg.defaultValue: 1.12840 + conversion = fill( 1.12841 + """ 1.12842 + if (${argName}.WasPassed()) { 1.12843 + $*{conversion} 1.12844 + } else if (argc == ${iPlus1}) { 1.12845 + // This is our current trailing argument; reduce argc 1.12846 + --argc; 1.12847 + } else { 1.12848 + argv[${i}] = JS::UndefinedValue(); 1.12849 + } 1.12850 + """, 1.12851 + argName=arg.identifier.name, 1.12852 + conversion=conversion, 1.12853 + iPlus1=i + 1, 1.12854 + i=i) 1.12855 + return conversion 1.12856 + 1.12857 + def getDefaultRetval(self): 1.12858 + default = self.getRetvalInfo(self.retvalType, False)[1] 1.12859 + if len(default) != 0: 1.12860 + default = " " + default 1.12861 + return default 1.12862 + 1.12863 + def getArgs(self, returnType, argList): 1.12864 + args = CGNativeMember.getArgs(self, returnType, argList) 1.12865 + if not self.needThisHandling: 1.12866 + # Since we don't need this handling, we're the actual method that 1.12867 + # will be called, so we need an aRethrowExceptions argument. 1.12868 + if self.rethrowContentException: 1.12869 + args.append(Argument("JSCompartment*", "aCompartment", "nullptr")) 1.12870 + else: 1.12871 + args.append(Argument("ExceptionHandling", "aExceptionHandling", 1.12872 + "eReportExceptions")) 1.12873 + return args 1.12874 + # We want to allow the caller to pass in a "this" value, as 1.12875 + # well as a JSContext. 1.12876 + return [Argument("JSContext*", "cx"), 1.12877 + Argument("JS::Handle<JS::Value>", "aThisVal")] + args 1.12878 + 1.12879 + def getCallSetup(self): 1.12880 + if self.needThisHandling: 1.12881 + # It's been done for us already 1.12882 + return "" 1.12883 + callSetup = "CallSetup s(this, aRv" 1.12884 + if self.rethrowContentException: 1.12885 + # getArgs doesn't add the aExceptionHandling argument but does add 1.12886 + # aCompartment for us. 1.12887 + callSetup += ", eRethrowContentExceptions, aCompartment, /* aIsJSImplementedWebIDL = */ " 1.12888 + callSetup += toStringBool(isJSImplementedDescriptor(self.descriptorProvider)) 1.12889 + else: 1.12890 + callSetup += ", aExceptionHandling" 1.12891 + callSetup += ");\n" 1.12892 + return fill( 1.12893 + """ 1.12894 + $*{callSetup} 1.12895 + JSContext* cx = s.GetContext(); 1.12896 + if (!cx) { 1.12897 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.12898 + return${errorReturn}; 1.12899 + } 1.12900 + """, 1.12901 + callSetup=callSetup, 1.12902 + errorReturn=self.getDefaultRetval()) 1.12903 + 1.12904 + def getArgcDecl(self): 1.12905 + return CGGeneric("unsigned argc = %s;\n" % self.argCountStr) 1.12906 + 1.12907 + @staticmethod 1.12908 + def ensureASCIIName(idlObject): 1.12909 + type = "attribute" if idlObject.isAttr() else "operation" 1.12910 + if re.match("[^\x20-\x7E]", idlObject.identifier.name): 1.12911 + raise SyntaxError('Callback %s name "%s" contains non-ASCII ' 1.12912 + "characters. We can't handle that. %s" % 1.12913 + (type, idlObject.identifier.name, 1.12914 + idlObject.location)) 1.12915 + if re.match('"', idlObject.identifier.name): 1.12916 + raise SyntaxError("Callback %s name '%s' contains " 1.12917 + "double-quote character. We can't handle " 1.12918 + "that. %s" % 1.12919 + (type, idlObject.identifier.name, 1.12920 + idlObject.location)) 1.12921 + 1.12922 + 1.12923 +class CallbackMethod(CallbackMember): 1.12924 + def __init__(self, sig, name, descriptorProvider, needThisHandling, 1.12925 + rethrowContentException=False): 1.12926 + CallbackMember.__init__(self, sig, name, descriptorProvider, 1.12927 + needThisHandling, rethrowContentException) 1.12928 + 1.12929 + def getRvalDecl(self): 1.12930 + return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n" 1.12931 + 1.12932 + def getCall(self): 1.12933 + if self.argCount > 0: 1.12934 + args = "JS::HandleValueArray::subarray(argv, 0, argc)" 1.12935 + else: 1.12936 + args = "JS::HandleValueArray::empty()" 1.12937 + 1.12938 + return fill( 1.12939 + """ 1.12940 + $*{declCallable} 1.12941 + $*{declThis} 1.12942 + if (${callGuard}!JS::Call(cx, ${thisVal}, callable, 1.12943 + ${args}, &rval)) { 1.12944 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.12945 + return${errorReturn}; 1.12946 + } 1.12947 + """, 1.12948 + declCallable=self.getCallableDecl(), 1.12949 + declThis=self.getThisDecl(), 1.12950 + callGuard=self.getCallGuard(), 1.12951 + thisVal=self.getThisVal(), 1.12952 + args=args, 1.12953 + errorReturn=self.getDefaultRetval()) 1.12954 + 1.12955 + 1.12956 +class CallCallback(CallbackMethod): 1.12957 + def __init__(self, callback, descriptorProvider): 1.12958 + self.callback = callback 1.12959 + CallbackMethod.__init__(self, callback.signatures()[0], "Call", 1.12960 + descriptorProvider, needThisHandling=True) 1.12961 + 1.12962 + def getThisDecl(self): 1.12963 + return "" 1.12964 + 1.12965 + def getThisVal(self): 1.12966 + return "aThisVal" 1.12967 + 1.12968 + def getCallableDecl(self): 1.12969 + return "JS::Rooted<JS::Value> callable(cx, JS::ObjectValue(*mCallback));\n" 1.12970 + 1.12971 + def getPrettyName(self): 1.12972 + return self.callback.identifier.name 1.12973 + 1.12974 + def getCallGuard(self): 1.12975 + if self.callback._treatNonObjectAsNull: 1.12976 + return "JS_ObjectIsCallable(cx, mCallback) && " 1.12977 + return "" 1.12978 + 1.12979 + 1.12980 +class CallbackOperationBase(CallbackMethod): 1.12981 + """ 1.12982 + Common class for implementing various callback operations. 1.12983 + """ 1.12984 + def __init__(self, signature, jsName, nativeName, descriptor, singleOperation, rethrowContentException=False): 1.12985 + self.singleOperation = singleOperation 1.12986 + self.methodName = descriptor.binaryNames.get(jsName, jsName) 1.12987 + CallbackMethod.__init__(self, signature, nativeName, descriptor, singleOperation, rethrowContentException) 1.12988 + 1.12989 + def getThisDecl(self): 1.12990 + if not self.singleOperation: 1.12991 + return "JS::Rooted<JS::Value> thisValue(cx, JS::ObjectValue(*mCallback));\n" 1.12992 + # This relies on getCallableDecl declaring a boolean 1.12993 + # isCallable in the case when we're a single-operation 1.12994 + # interface. 1.12995 + return dedent(""" 1.12996 + JS::Rooted<JS::Value> thisValue(cx, isCallable ? aThisVal.get() 1.12997 + : JS::ObjectValue(*mCallback)); 1.12998 + """) 1.12999 + 1.13000 + def getThisVal(self): 1.13001 + return "thisValue" 1.13002 + 1.13003 + def getCallableDecl(self): 1.13004 + getCallableFromProp = fill( 1.13005 + """ 1.13006 + if (!GetCallableProperty(cx, "${methodName}", &callable)) { 1.13007 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.13008 + return${errorReturn}; 1.13009 + } 1.13010 + """, 1.13011 + methodName=self.methodName, 1.13012 + errorReturn=self.getDefaultRetval()) 1.13013 + if not self.singleOperation: 1.13014 + return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp 1.13015 + return fill( 1.13016 + """ 1.13017 + bool isCallable = JS_ObjectIsCallable(cx, mCallback); 1.13018 + JS::Rooted<JS::Value> callable(cx); 1.13019 + if (isCallable) { 1.13020 + callable = JS::ObjectValue(*mCallback); 1.13021 + } else { 1.13022 + $*{getCallableFromProp} 1.13023 + } 1.13024 + """, 1.13025 + getCallableFromProp=getCallableFromProp) 1.13026 + 1.13027 + def getCallGuard(self): 1.13028 + return "" 1.13029 + 1.13030 + 1.13031 +class CallbackOperation(CallbackOperationBase): 1.13032 + """ 1.13033 + Codegen actual WebIDL operations on callback interfaces. 1.13034 + """ 1.13035 + def __init__(self, method, signature, descriptor): 1.13036 + self.ensureASCIIName(method) 1.13037 + self.method = method 1.13038 + jsName = method.identifier.name 1.13039 + CallbackOperationBase.__init__(self, signature, 1.13040 + jsName, 1.13041 + MakeNativeName(descriptor.binaryNames.get(jsName, jsName)), 1.13042 + descriptor, descriptor.interface.isSingleOperationInterface(), 1.13043 + rethrowContentException=descriptor.interface.isJSImplemented()) 1.13044 + 1.13045 + def getPrettyName(self): 1.13046 + return "%s.%s" % (self.descriptorProvider.interface.identifier.name, 1.13047 + self.method.identifier.name) 1.13048 + 1.13049 + 1.13050 +class CallbackAccessor(CallbackMember): 1.13051 + """ 1.13052 + Shared superclass for CallbackGetter and CallbackSetter. 1.13053 + """ 1.13054 + def __init__(self, attr, sig, name, descriptor): 1.13055 + self.ensureASCIIName(attr) 1.13056 + self.attrName = attr.identifier.name 1.13057 + CallbackMember.__init__(self, sig, name, descriptor, 1.13058 + needThisHandling=False, 1.13059 + rethrowContentException=descriptor.interface.isJSImplemented()) 1.13060 + 1.13061 + def getPrettyName(self): 1.13062 + return "%s.%s" % (self.descriptorProvider.interface.identifier.name, 1.13063 + self.attrName) 1.13064 + 1.13065 + 1.13066 +class CallbackGetter(CallbackAccessor): 1.13067 + def __init__(self, attr, descriptor): 1.13068 + CallbackAccessor.__init__(self, attr, 1.13069 + (attr.type, []), 1.13070 + callbackGetterName(attr, descriptor), 1.13071 + descriptor) 1.13072 + 1.13073 + def getRvalDecl(self): 1.13074 + return "JS::Rooted<JS::Value> rval(cx, JS::UndefinedValue());\n" 1.13075 + 1.13076 + def getCall(self): 1.13077 + return fill( 1.13078 + """ 1.13079 + JS::Rooted<JSObject *> callback(cx, mCallback); 1.13080 + if (!JS_GetProperty(cx, callback, "${attrName}", &rval)) { 1.13081 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.13082 + return${errorReturn}; 1.13083 + } 1.13084 + """, 1.13085 + attrName=self.descriptorProvider.binaryNames.get(self.attrName, 1.13086 + self.attrName), 1.13087 + errorReturn=self.getDefaultRetval()) 1.13088 + 1.13089 + 1.13090 +class CallbackSetter(CallbackAccessor): 1.13091 + def __init__(self, attr, descriptor): 1.13092 + CallbackAccessor.__init__(self, attr, 1.13093 + (BuiltinTypes[IDLBuiltinType.Types.void], 1.13094 + [FakeArgument(attr.type, attr)]), 1.13095 + callbackSetterName(attr, descriptor), 1.13096 + descriptor) 1.13097 + 1.13098 + def getRvalDecl(self): 1.13099 + # We don't need an rval 1.13100 + return "" 1.13101 + 1.13102 + def getCall(self): 1.13103 + return fill( 1.13104 + """ 1.13105 + MOZ_ASSERT(argv.length() == 1); 1.13106 + if (!JS_SetProperty(cx, CallbackPreserveColor(), "${attrName}", argv.handleAt(0))) { 1.13107 + aRv.Throw(NS_ERROR_UNEXPECTED); 1.13108 + return${errorReturn}; 1.13109 + } 1.13110 + """, 1.13111 + attrName=self.descriptorProvider.binaryNames.get(self.attrName, 1.13112 + self.attrName), 1.13113 + errorReturn=self.getDefaultRetval()) 1.13114 + 1.13115 + def getArgcDecl(self): 1.13116 + return None 1.13117 + 1.13118 + 1.13119 +class CGJSImplInitOperation(CallbackOperationBase): 1.13120 + """ 1.13121 + Codegen the __Init() method used to pass along constructor arguments for JS-implemented WebIDL. 1.13122 + """ 1.13123 + def __init__(self, sig, descriptor): 1.13124 + assert sig in descriptor.interface.ctor().signatures() 1.13125 + CallbackOperationBase.__init__(self, (BuiltinTypes[IDLBuiltinType.Types.void], sig[1]), 1.13126 + "__init", "__Init", descriptor, False, True) 1.13127 + 1.13128 + def getPrettyName(self): 1.13129 + return "__init" 1.13130 + 1.13131 + 1.13132 +class GlobalGenRoots(): 1.13133 + """ 1.13134 + Roots for global codegen. 1.13135 + 1.13136 + To generate code, call the method associated with the target, and then 1.13137 + call the appropriate define/declare method. 1.13138 + """ 1.13139 + 1.13140 + @staticmethod 1.13141 + def GeneratedAtomList(config): 1.13142 + # Atom enum 1.13143 + dictionaries = config.dictionaries 1.13144 + 1.13145 + structs = [] 1.13146 + 1.13147 + for dict in dictionaries: 1.13148 + dictMembers = dict.members 1.13149 + if len(dictMembers) == 0: 1.13150 + continue 1.13151 + 1.13152 + classMembers = [ClassMember(CGDictionary.makeIdName(m.identifier.name), 1.13153 + "InternedStringId", 1.13154 + visibility="public") for m in dictMembers] 1.13155 + 1.13156 + structName = dict.identifier.name + "Atoms" 1.13157 + structs.append((structName, 1.13158 + CGWrapper(CGClass(structName, 1.13159 + bases=None, 1.13160 + isStruct=True, 1.13161 + members=classMembers), post='\n'))) 1.13162 + 1.13163 + structs.sort() 1.13164 + generatedStructs = [struct for structName, struct in structs] 1.13165 + structNames = [structName for structName, struct in structs] 1.13166 + 1.13167 + mainStruct = CGWrapper(CGClass("PerThreadAtomCache", 1.13168 + bases=[ClassBase(structName) for structName in structNames], 1.13169 + isStruct=True), 1.13170 + post='\n') 1.13171 + 1.13172 + structs = CGList(generatedStructs + [mainStruct]) 1.13173 + 1.13174 + # Wrap all of that in our namespaces. 1.13175 + curr = CGNamespace.build(['mozilla', 'dom'], 1.13176 + CGWrapper(structs, pre='\n')) 1.13177 + curr = CGWrapper(curr, post='\n') 1.13178 + 1.13179 + # Add include statement for InternedStringId. 1.13180 + declareIncludes = ['mozilla/dom/BindingUtils.h'] 1.13181 + curr = CGHeaders([], [], [], [], declareIncludes, [], 'GeneratedAtomList', 1.13182 + curr) 1.13183 + 1.13184 + # Add include guards. 1.13185 + curr = CGIncludeGuard('GeneratedAtomList', curr) 1.13186 + 1.13187 + # Add the auto-generated comment. 1.13188 + curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) 1.13189 + 1.13190 + # Done. 1.13191 + return curr 1.13192 + 1.13193 + @staticmethod 1.13194 + def PrototypeList(config): 1.13195 + 1.13196 + # Prototype ID enum. 1.13197 + descriptorsWithPrototype = config.getDescriptors(hasInterfacePrototypeObject=True) 1.13198 + protos = [d.name for d in descriptorsWithPrototype] 1.13199 + idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + protos, 1.13200 + [0, '_ID_Start']) 1.13201 + idEnum = CGList([idEnum]) 1.13202 + 1.13203 + # This is only used by DOM worker code, once there are no more consumers 1.13204 + # of INTERFACE_CHAIN_* this code should be removed. 1.13205 + def ifaceChainMacro(ifaceCount): 1.13206 + supplied = [CGGeneric(declare="_iface_" + str(i + 1)) for i in range(ifaceCount)] 1.13207 + remaining = [CGGeneric(declare="prototypes::id::_ID_Count")] * (config.maxProtoChainLength - ifaceCount) 1.13208 + macro = CGWrapper(CGList(supplied, ", "), 1.13209 + pre="#define INTERFACE_CHAIN_" + str(ifaceCount) + "(", 1.13210 + post=") \\\n", 1.13211 + declareOnly=True) 1.13212 + macroContent = CGIndenter(CGList(supplied + remaining, ", \\\n")) 1.13213 + macroContent = CGIndenter(CGWrapper(macroContent, pre="{ \\\n", 1.13214 + post=" \\\n}", 1.13215 + declareOnly=True)) 1.13216 + return CGWrapper(CGList([macro, macroContent]), post="\n\n", 1.13217 + declareOnly=True) 1.13218 + 1.13219 + idEnum.append(ifaceChainMacro(1)) 1.13220 + 1.13221 + def fieldSizeAssert(amount, jitInfoField, message): 1.13222 + maxFieldValue = "(uint64_t(1) << (sizeof(((JSJitInfo*)nullptr)->%s) * 8))" % jitInfoField 1.13223 + return CGGeneric(declare="static_assert(%s < %s, \"%s\");\n\n" 1.13224 + % (amount, maxFieldValue, message)) 1.13225 + 1.13226 + idEnum.append(fieldSizeAssert("id::_ID_Count", "protoID", 1.13227 + "Too many prototypes!")) 1.13228 + 1.13229 + # Wrap all of that in our namespaces. 1.13230 + idEnum = CGNamespace.build(['mozilla', 'dom', 'prototypes'], 1.13231 + CGWrapper(idEnum, pre='\n')) 1.13232 + idEnum = CGWrapper(idEnum, post='\n') 1.13233 + 1.13234 + curr = CGList([CGGeneric(define="#include <stdint.h>\n\n"), 1.13235 + idEnum]) 1.13236 + 1.13237 + # Let things know the maximum length of the prototype chain. 1.13238 + maxMacroName = "MAX_PROTOTYPE_CHAIN_LENGTH" 1.13239 + maxMacro = CGGeneric(declare="#define " + maxMacroName + " " + str(config.maxProtoChainLength)) 1.13240 + curr.append(CGWrapper(maxMacro, post='\n\n')) 1.13241 + curr.append(fieldSizeAssert(maxMacroName, "depth", 1.13242 + "Some inheritance chain is too long!")) 1.13243 + 1.13244 + # Constructor ID enum. 1.13245 + constructors = [d.name for d in config.getDescriptors(hasInterfaceObject=True)] 1.13246 + idEnum = CGNamespacedEnum('id', 'ID', ['_ID_Start'] + constructors, 1.13247 + ['prototypes::id::_ID_Count', '_ID_Start']) 1.13248 + 1.13249 + # Wrap all of that in our namespaces. 1.13250 + idEnum = CGNamespace.build(['mozilla', 'dom', 'constructors'], 1.13251 + CGWrapper(idEnum, pre='\n')) 1.13252 + idEnum = CGWrapper(idEnum, post='\n') 1.13253 + 1.13254 + curr.append(idEnum) 1.13255 + 1.13256 + traitsDecls = [CGGeneric(declare=dedent(""" 1.13257 + template <prototypes::ID PrototypeID> 1.13258 + struct PrototypeTraits; 1.13259 + """))] 1.13260 + traitsDecls.extend(CGPrototypeTraitsClass(d) for d in descriptorsWithPrototype) 1.13261 + 1.13262 + ifaceNamesWithProto = [d.interface.identifier.name 1.13263 + for d in descriptorsWithPrototype] 1.13264 + traitsDecls.append(CGStringTable("NamesOfInterfacesWithProtos", 1.13265 + ifaceNamesWithProto)) 1.13266 + 1.13267 + traitsDecl = CGNamespace.build(['mozilla', 'dom'], 1.13268 + CGList(traitsDecls)) 1.13269 + 1.13270 + curr.append(traitsDecl) 1.13271 + 1.13272 + # Add include guards. 1.13273 + curr = CGIncludeGuard('PrototypeList', curr) 1.13274 + 1.13275 + # Add the auto-generated comment. 1.13276 + curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT) 1.13277 + 1.13278 + # Done. 1.13279 + return curr 1.13280 + 1.13281 + @staticmethod 1.13282 + def RegisterBindings(config): 1.13283 + 1.13284 + # TODO - Generate the methods we want 1.13285 + curr = CGRegisterProtos(config) 1.13286 + 1.13287 + # Wrap all of that in our namespaces. 1.13288 + curr = CGNamespace.build(['mozilla', 'dom'], 1.13289 + CGWrapper(curr, post='\n')) 1.13290 + curr = CGWrapper(curr, post='\n') 1.13291 + 1.13292 + # Add the includes 1.13293 + defineIncludes = [CGHeaders.getDeclarationFilename(desc.interface) 1.13294 + for desc in config.getDescriptors(hasInterfaceObject=True, 1.13295 + workers=False, 1.13296 + register=True)] 1.13297 + defineIncludes.append('nsScriptNameSpaceManager.h') 1.13298 + defineIncludes.extend([CGHeaders.getDeclarationFilename(desc.interface) 1.13299 + for desc in config.getDescriptors(isNavigatorProperty=True, 1.13300 + workers=False, 1.13301 + register=True)]) 1.13302 + curr = CGHeaders([], [], [], [], [], defineIncludes, 'RegisterBindings', 1.13303 + curr) 1.13304 + 1.13305 + # Add include guards. 1.13306 + curr = CGIncludeGuard('RegisterBindings', curr) 1.13307 + 1.13308 + # Done. 1.13309 + return curr 1.13310 + 1.13311 + @staticmethod 1.13312 + def UnionTypes(config): 1.13313 + 1.13314 + (includes, implincludes, 1.13315 + declarations, unions) = UnionTypes(config.getDescriptors(), 1.13316 + config.getDictionaries(), 1.13317 + config.getCallbacks(), 1.13318 + config) 1.13319 + includes.add("mozilla/dom/OwningNonNull.h") 1.13320 + includes.add("mozilla/dom/UnionMember.h") 1.13321 + includes.add("mozilla/dom/BindingDeclarations.h") 1.13322 + # Need BindingUtils.h for FakeDependentString 1.13323 + includes.add("mozilla/dom/BindingUtils.h") 1.13324 + implincludes.add("mozilla/dom/PrimitiveConversions.h") 1.13325 + 1.13326 + # Wrap all of that in our namespaces. 1.13327 + curr = CGNamespace.build(['mozilla', 'dom'], unions) 1.13328 + 1.13329 + curr = CGWrapper(curr, post='\n') 1.13330 + 1.13331 + namespaces = [] 1.13332 + stack = [CGList([])] 1.13333 + for clazz, isStruct in sorted(declarations): 1.13334 + elements = clazz.split("::") 1.13335 + clazz = CGClassForwardDeclare(elements.pop(), isStruct=isStruct) 1.13336 + i = 0 1.13337 + if len(elements) > 0: 1.13338 + common = min(len(namespaces), len(elements)) 1.13339 + while i < common and namespaces[i] == elements[i]: 1.13340 + i += 1 1.13341 + 1.13342 + # pop all the namespaces that should be closed 1.13343 + namespaces = namespaces[:i] 1.13344 + 1.13345 + # add all the namespaces that should be opened 1.13346 + for j, namespace in enumerate(elements[i:]): 1.13347 + namespaces.append(namespace) 1.13348 + # every CGNamespace that we add holds a CGList 1.13349 + list = CGList([]) 1.13350 + # add the new namespace to the list on top of the stack 1.13351 + stack[i + j].append(CGNamespace(namespace, list)) 1.13352 + # set the top of the namespace stack to the list of the new 1.13353 + # namespace 1.13354 + stack[i + j + 1:] = [list] 1.13355 + 1.13356 + stack[len(elements)].append(clazz) 1.13357 + 1.13358 + curr = CGList([stack[0], curr], "\n") 1.13359 + 1.13360 + curr = CGHeaders([], [], [], [], includes, implincludes, 'UnionTypes', 1.13361 + curr) 1.13362 + 1.13363 + # Add include guards. 1.13364 + curr = CGIncludeGuard('UnionTypes', curr) 1.13365 + 1.13366 + # Done. 1.13367 + return curr 1.13368 + 1.13369 + @staticmethod 1.13370 + def UnionConversions(config): 1.13371 + 1.13372 + headers, unions = UnionConversions(config.getDescriptors(), 1.13373 + config.getDictionaries(), 1.13374 + config.getCallbacks(), 1.13375 + config) 1.13376 + 1.13377 + # Wrap all of that in our namespaces. 1.13378 + curr = CGNamespace.build(['mozilla', 'dom'], unions) 1.13379 + 1.13380 + curr = CGWrapper(curr, post='\n') 1.13381 + 1.13382 + headers.update(["nsDebug.h", "mozilla/dom/UnionTypes.h"]) 1.13383 + curr = CGHeaders([], [], [], [], headers, [], 'UnionConversions', curr) 1.13384 + 1.13385 + # Add include guards. 1.13386 + curr = CGIncludeGuard('UnionConversions', curr) 1.13387 + 1.13388 + # Done. 1.13389 + return curr 1.13390 + 1.13391 + 1.13392 +# Code generator for simple events 1.13393 +class CGEventGetter(CGNativeMember): 1.13394 + def __init__(self, descriptor, attr): 1.13395 + ea = descriptor.getExtendedAttributes(attr, getter=True) 1.13396 + ea.append('resultNotAddRefed') 1.13397 + CGNativeMember.__init__(self, descriptor, attr, 1.13398 + CGSpecializedGetter.makeNativeName(descriptor, 1.13399 + attr), 1.13400 + (attr.type, []), 1.13401 + ea) 1.13402 + self.body = self.getMethodBody() 1.13403 + 1.13404 + def getArgs(self, returnType, argList): 1.13405 + if 'infallible' not in self.extendedAttrs: 1.13406 + raise TypeError("Event code generator does not support [Throws]!") 1.13407 + if not self.member.isAttr(): 1.13408 + raise TypeError("Event code generator does not support methods") 1.13409 + if self.member.isStatic(): 1.13410 + raise TypeError("Event code generators does not support static attributes") 1.13411 + return CGNativeMember.getArgs(self, returnType, argList) 1.13412 + 1.13413 + def getMethodBody(self): 1.13414 + type = self.member.type 1.13415 + memberName = CGDictionary.makeMemberName(self.member.identifier.name) 1.13416 + if (type.isPrimitive() and type.tag() in builtinNames) or type.isEnum() or type.isGeckoInterface(): 1.13417 + return "return " + memberName + ";\n" 1.13418 + if type.isDOMString() or type.isByteString(): 1.13419 + return "aRetVal = " + memberName + ";\n" 1.13420 + if type.isSpiderMonkeyInterface() or type.isObject(): 1.13421 + return fill( 1.13422 + """ 1.13423 + if (${memberName}) { 1.13424 + JS::ExposeObjectToActiveJS(${memberName}); 1.13425 + } 1.13426 + aRetVal.set(${memberName}); 1.13427 + return; 1.13428 + """, 1.13429 + memberName=memberName) 1.13430 + if type.isAny(): 1.13431 + return fill( 1.13432 + """ 1.13433 + JS::ExposeValueToActiveJS(${memberName}); 1.13434 + aRetVal.set(${memberName}); 1.13435 + return; 1.13436 + """, 1.13437 + memberName=memberName) 1.13438 + if type.isUnion(): 1.13439 + return "aRetVal = " + memberName + ";\n" 1.13440 + raise TypeError("Event code generator does not support this type!") 1.13441 + 1.13442 + def declare(self, cgClass): 1.13443 + if getattr(self.member, "originatingInterface", 1.13444 + cgClass.descriptor.interface) != cgClass.descriptor.interface: 1.13445 + return "" 1.13446 + return CGNativeMember.declare(self, cgClass) 1.13447 + 1.13448 + def define(self, cgClass): 1.13449 + if getattr(self.member, "originatingInterface", 1.13450 + cgClass.descriptor.interface) != cgClass.descriptor.interface: 1.13451 + return "" 1.13452 + return CGNativeMember.define(self, cgClass) 1.13453 + 1.13454 + 1.13455 +class CGEventSetter(CGNativeMember): 1.13456 + def __init__(self): 1.13457 + raise TypeError("Event code generator does not support setters!") 1.13458 + 1.13459 + 1.13460 +class CGEventMethod(CGNativeMember): 1.13461 + def __init__(self, descriptor, method, signature, isConstructor, breakAfter=True): 1.13462 + if not isConstructor: 1.13463 + raise TypeError("Event code generator does not support methods!") 1.13464 + self.wantsConstructorForNativeCaller = True 1.13465 + CGNativeMember.__init__(self, descriptor, method, 1.13466 + CGSpecializedMethod.makeNativeName(descriptor, 1.13467 + method), 1.13468 + signature, 1.13469 + descriptor.getExtendedAttributes(method), 1.13470 + breakAfter=breakAfter, 1.13471 + variadicIsSequence=True) 1.13472 + self.originalArgs = list(self.args) 1.13473 + 1.13474 + def getArgs(self, returnType, argList): 1.13475 + args = [self.getArg(arg) for arg in argList] 1.13476 + return args 1.13477 + 1.13478 + def getArg(self, arg): 1.13479 + decl, ref = self.getArgType(arg.type, 1.13480 + arg.optional and not arg.defaultValue, 1.13481 + "Variadic" if arg.variadic else False) 1.13482 + if ref: 1.13483 + decl = CGWrapper(decl, pre="const ", post="&") 1.13484 + 1.13485 + name = arg.identifier.name 1.13486 + name = "a" + name[0].upper() + name[1:] 1.13487 + return Argument(decl.define(), name) 1.13488 + 1.13489 + def declare(self, cgClass): 1.13490 + self.args = list(self.originalArgs) 1.13491 + self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner")) 1.13492 + constructorForNativeCaller = CGNativeMember.declare(self, cgClass) + "\n" 1.13493 + self.args = list(self.originalArgs) 1.13494 + if needCx(None, self.descriptorProvider.interface.members, [], True): 1.13495 + self.args.insert(0, Argument("JSContext*", "aCx")) 1.13496 + self.args.insert(0, Argument("const GlobalObject&", "aGlobal")) 1.13497 + self.args.append(Argument('ErrorResult&', 'aRv')) 1.13498 + return constructorForNativeCaller + CGNativeMember.declare(self, cgClass) 1.13499 + 1.13500 + def define(self, cgClass): 1.13501 + self.args = list(self.originalArgs) 1.13502 + members = "" 1.13503 + holdJS = "" 1.13504 + iface = self.descriptorProvider.interface 1.13505 + while iface.identifier.name != "Event": 1.13506 + for m in self.descriptorProvider.getDescriptor(iface.identifier.name).interface.members: 1.13507 + if m.isAttr(): 1.13508 + # We initialize all the other member variables in the 1.13509 + # Constructor except those ones coming from the Event. 1.13510 + if getattr(m, "originatingInterface", 1.13511 + cgClass.descriptor.interface).identifier.name == "Event": 1.13512 + continue 1.13513 + name = CGDictionary.makeMemberName(m.identifier.name) 1.13514 + members += "e->%s = %s.%s;\n" % (name, self.args[1].name, name) 1.13515 + if m.type.isAny() or m.type.isObject() or m.type.isSpiderMonkeyInterface(): 1.13516 + holdJS = "mozilla::HoldJSObjects(e.get());\n" 1.13517 + iface = iface.parent 1.13518 + 1.13519 + self.body = fill( 1.13520 + """ 1.13521 + nsRefPtr<${nativeType}> e = new ${nativeType}(aOwner); 1.13522 + bool trusted = e->Init(aOwner); 1.13523 + e->InitEvent(${eventType}, ${eventInit}.mBubbles, ${eventInit}.mCancelable); 1.13524 + $*{members} 1.13525 + e->SetTrusted(trusted); 1.13526 + $*{holdJS} 1.13527 + return e.forget(); 1.13528 + """, 1.13529 + nativeType=self.descriptorProvider.nativeType.split('::')[-1], 1.13530 + eventType=self.args[0].name, 1.13531 + eventInit=self.args[1].name, 1.13532 + members=members, 1.13533 + holdJS=holdJS) 1.13534 + 1.13535 + self.args.insert(0, Argument("mozilla::dom::EventTarget*", "aOwner")) 1.13536 + constructorForNativeCaller = CGNativeMember.define(self, cgClass) + "\n" 1.13537 + self.args = list(self.originalArgs) 1.13538 + self.body = fill( 1.13539 + """ 1.13540 + nsCOMPtr<mozilla::dom::EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports()); 1.13541 + return Constructor(owner, ${arg0}, ${arg1}); 1.13542 + """, 1.13543 + arg0=self.args[0].name, 1.13544 + arg1=self.args[1].name) 1.13545 + if needCx(None, self.descriptorProvider.interface.members, [], True): 1.13546 + self.args.insert(0, Argument("JSContext*", "aCx")) 1.13547 + self.args.insert(0, Argument("const GlobalObject&", "aGlobal")) 1.13548 + self.args.append(Argument('ErrorResult&', 'aRv')) 1.13549 + return constructorForNativeCaller + CGNativeMember.define(self, cgClass) 1.13550 + 1.13551 + 1.13552 +class CGEventClass(CGBindingImplClass): 1.13553 + """ 1.13554 + Codegen for the actual Event class implementation for this descriptor 1.13555 + """ 1.13556 + def __init__(self, descriptor): 1.13557 + CGBindingImplClass.__init__(self, descriptor, CGEventMethod, CGEventGetter, CGEventSetter, False) 1.13558 + members = [] 1.13559 + for m in descriptor.interface.members: 1.13560 + if m.isAttr(): 1.13561 + if getattr(m, "originatingInterface", 1.13562 + descriptor.interface) != descriptor.interface: 1.13563 + continue 1.13564 + if m.type.isPrimitive() and m.type.tag() in builtinNames: 1.13565 + nativeType = CGGeneric(builtinNames[m.type.tag()]) 1.13566 + if m.type.nullable(): 1.13567 + nativeType = CGTemplatedType("Nullable", nativeType) 1.13568 + nativeType = nativeType.define() 1.13569 + elif m.type.isEnum(): 1.13570 + nativeType = m.type.unroll().inner.identifier.name 1.13571 + if m.type.nullable(): 1.13572 + nativeType = CGTemplatedType("Nullable", 1.13573 + CGGeneric(nativeType)).define() 1.13574 + elif m.type.isDOMString(): 1.13575 + nativeType = "nsString" 1.13576 + elif m.type.isByteString(): 1.13577 + nativeType = "nsCString" 1.13578 + elif m.type.isGeckoInterface(): 1.13579 + iface = m.type.unroll().inner 1.13580 + nativeType = self.descriptor.getDescriptor( 1.13581 + iface.identifier.name).nativeType 1.13582 + # Now trim off unnecessary namespaces 1.13583 + nativeType = nativeType.split("::") 1.13584 + if nativeType[0] == "mozilla": 1.13585 + nativeType.pop(0) 1.13586 + if nativeType[0] == "dom": 1.13587 + nativeType.pop(0) 1.13588 + nativeType = CGWrapper(CGGeneric("::".join(nativeType)), pre="nsRefPtr<", post=">").define() 1.13589 + elif m.type.isAny(): 1.13590 + nativeType = "JS::Heap<JS::Value>" 1.13591 + elif m.type.isObject() or m.type.isSpiderMonkeyInterface(): 1.13592 + nativeType = "JS::Heap<JSObject*>" 1.13593 + elif m.type.isUnion(): 1.13594 + nativeType = CGUnionStruct.unionTypeDecl(m.type, True) 1.13595 + else: 1.13596 + raise TypeError("Don't know how to declare member of type %s" % 1.13597 + m.type) 1.13598 + members.append(ClassMember(CGDictionary.makeMemberName(m.identifier.name), 1.13599 + nativeType, 1.13600 + visibility="private", 1.13601 + body="body")) 1.13602 + 1.13603 + parent = self.descriptor.interface.parent 1.13604 + self.parentType = self.descriptor.getDescriptor(parent.identifier.name).nativeType.split('::')[-1] 1.13605 + baseDeclarations = fill( 1.13606 + """ 1.13607 + public: 1.13608 + NS_DECL_ISUPPORTS_INHERITED 1.13609 + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(${nativeType}, ${parentType}) 1.13610 + virtual ~${nativeType}(); 1.13611 + protected: 1.13612 + ${nativeType}(mozilla::dom::EventTarget* aOwner); 1.13613 + 1.13614 + """, 1.13615 + nativeType=self.descriptor.nativeType.split('::')[-1], 1.13616 + parentType=self.parentType) 1.13617 + 1.13618 + className = descriptor.nativeType.split('::')[-1] 1.13619 + asConcreteTypeMethod = ClassMethod("As%s" % className, 1.13620 + "%s*" % className, 1.13621 + [], 1.13622 + virtual=True, 1.13623 + body="return this;\n", 1.13624 + breakAfterReturnDecl=" ") 1.13625 + 1.13626 + CGClass.__init__(self, className, 1.13627 + bases=[ClassBase(self.parentType)], 1.13628 + methods=[asConcreteTypeMethod]+self.methodDecls, 1.13629 + members=members, 1.13630 + extradeclarations=baseDeclarations) 1.13631 + 1.13632 + def getWrapObjectBody(self): 1.13633 + return "return %sBinding::Wrap(aCx, this);\n" % self.descriptor.name 1.13634 + 1.13635 + def implTraverse(self): 1.13636 + retVal = "" 1.13637 + for m in self.descriptor.interface.members: 1.13638 + if m.isAttr() and m.type.isGeckoInterface(): 1.13639 + retVal += (" NS_IMPL_CYCLE_COLLECTION_TRAVERSE(" + 1.13640 + CGDictionary.makeMemberName(m.identifier.name) + 1.13641 + ")\n") 1.13642 + return retVal 1.13643 + 1.13644 + def implUnlink(self): 1.13645 + retVal = "" 1.13646 + for m in self.descriptor.interface.members: 1.13647 + if m.isAttr(): 1.13648 + name = CGDictionary.makeMemberName(m.identifier.name) 1.13649 + if m.type.isGeckoInterface(): 1.13650 + retVal += " NS_IMPL_CYCLE_COLLECTION_UNLINK(" + name + ")\n" 1.13651 + elif m.type.isAny(): 1.13652 + retVal += " tmp->" + name + ".setUndefined();\n" 1.13653 + elif m.type.isObject() or m.type.isSpiderMonkeyInterface(): 1.13654 + retVal += " tmp->" + name + " = nullptr;\n" 1.13655 + return retVal 1.13656 + 1.13657 + def implTrace(self): 1.13658 + retVal = "" 1.13659 + for m in self.descriptor.interface.members: 1.13660 + if m.isAttr(): 1.13661 + name = CGDictionary.makeMemberName(m.identifier.name) 1.13662 + if m.type.isAny(): 1.13663 + retVal += " NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(" + name + ")\n" 1.13664 + elif m.type.isObject() or m.type.isSpiderMonkeyInterface(): 1.13665 + retVal += " NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(" + name + ")\n" 1.13666 + elif typeNeedsRooting(m.type): 1.13667 + raise TypeError("Need to implement tracing for event " 1.13668 + "member of type %s" % m.type) 1.13669 + return retVal 1.13670 + 1.13671 + def define(self): 1.13672 + dropJS = "" 1.13673 + for m in self.descriptor.interface.members: 1.13674 + if m.isAttr(): 1.13675 + member = CGDictionary.makeMemberName(m.identifier.name) 1.13676 + if m.type.isAny(): 1.13677 + dropJS += member + " = JS::UndefinedValue();\n" 1.13678 + elif m.type.isObject() or m.type.isSpiderMonkeyInterface(): 1.13679 + dropJS += member + " = nullptr;\n" 1.13680 + if dropJS != "": 1.13681 + dropJS += "mozilla::DropJSObjects(this);\n" 1.13682 + # Just override CGClass and do our own thing 1.13683 + nativeType = self.descriptor.nativeType.split('::')[-1] 1.13684 + ctorParams = ("aOwner, nullptr, nullptr" if self.parentType == "Event" 1.13685 + else "aOwner") 1.13686 + 1.13687 + classImpl = fill( 1.13688 + """ 1.13689 + 1.13690 + NS_IMPL_CYCLE_COLLECTION_CLASS(${nativeType}) 1.13691 + 1.13692 + NS_IMPL_ADDREF_INHERITED(${nativeType}, ${parentType}) 1.13693 + NS_IMPL_RELEASE_INHERITED(${nativeType}, ${parentType}) 1.13694 + 1.13695 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(${nativeType}, ${parentType}) 1.13696 + $*{traverse} 1.13697 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.13698 + 1.13699 + NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(${nativeType}, ${parentType}) 1.13700 + $*{trace} 1.13701 + NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.13702 + 1.13703 + NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(${nativeType}, ${parentType}) 1.13704 + $*{unlink} 1.13705 + NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.13706 + 1.13707 + NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(${nativeType}) 1.13708 + NS_INTERFACE_MAP_END_INHERITING(${parentType}) 1.13709 + 1.13710 + ${nativeType}::${nativeType}(mozilla::dom::EventTarget* aOwner) 1.13711 + : ${parentType}(${ctorParams}) 1.13712 + { 1.13713 + } 1.13714 + 1.13715 + ${nativeType}::~${nativeType}() 1.13716 + { 1.13717 + $*{dropJS} 1.13718 + } 1.13719 + 1.13720 + """, 1.13721 + ifaceName=self.descriptor.name, 1.13722 + nativeType=nativeType, 1.13723 + ctorParams=ctorParams, 1.13724 + parentType=self.parentType, 1.13725 + traverse=self.implTraverse(), 1.13726 + unlink=self.implUnlink(), 1.13727 + trace=self.implTrace(), 1.13728 + dropJS=dropJS) 1.13729 + return classImpl + CGBindingImplClass.define(self) 1.13730 + 1.13731 + 1.13732 +class CGEventRoot(CGThing): 1.13733 + def __init__(self, config, interfaceName): 1.13734 + # Let's assume we're not doing workers stuff, for now 1.13735 + descriptor = config.getDescriptor(interfaceName, False) 1.13736 + 1.13737 + self.root = CGWrapper(CGEventClass(descriptor), 1.13738 + pre="\n", post="\n") 1.13739 + 1.13740 + self.root = CGNamespace.build(["mozilla", "dom"], self.root) 1.13741 + 1.13742 + self.root = CGList([CGClassForwardDeclare("JSContext", isStruct=True), 1.13743 + self.root]) 1.13744 + 1.13745 + parent = descriptor.interface.parent.identifier.name 1.13746 + 1.13747 + # Throw in our #includes 1.13748 + self.root = CGHeaders([descriptor], [], [], [], 1.13749 + [ 1.13750 + config.getDescriptor(parent, False).headerFile, 1.13751 + "mozilla/Attributes.h", 1.13752 + "mozilla/ErrorResult.h", 1.13753 + "mozilla/dom/%sBinding.h" % interfaceName, 1.13754 + 'mozilla/dom/BindingUtils.h', 1.13755 + ], 1.13756 + [ 1.13757 + "%s.h" % interfaceName, 1.13758 + "js/GCAPI.h", 1.13759 + 'mozilla/dom/Nullable.h', 1.13760 + 'nsDOMQS.h' 1.13761 + ], 1.13762 + "", self.root) 1.13763 + 1.13764 + # And now some include guards 1.13765 + self.root = CGIncludeGuard(interfaceName, self.root) 1.13766 + 1.13767 + self.root = CGWrapper(self.root, pre=AUTOGENERATED_WARNING_COMMENT) 1.13768 + 1.13769 + self.root = CGWrapper(self.root, pre=dedent(""" 1.13770 + /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.13771 + /* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.13772 + /* This Source Code Form is subject to the terms of the Mozilla Public 1.13773 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.13774 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.13775 + 1.13776 + """)) 1.13777 + 1.13778 + def declare(self): 1.13779 + return self.root.declare() 1.13780 + 1.13781 + def define(self): 1.13782 + return self.root.define()