auto merge of #573 : jdm/servo/domevent, r=metajack

This commit is contained in:
bors-servo 2013-07-12 08:45:33 -07:00
commit 0c4119b496
16 changed files with 895 additions and 146 deletions

View file

@ -24,16 +24,21 @@ def replaceFileIfChanged(filename, newContents):
Read a copy of the old file, so that we don't touch it if it hasn't changed.
Returns True if the file was updated, false otherwise.
"""
oldFileContents = ""
try:
oldFile = open(filename, 'rb')
oldFileContents = ''.join(oldFile.readlines())
oldFile.close()
except:
pass
#XXXjdm This doesn't play well with make right now.
# Force the file to always be updated, or else changing CodegenRust.py
# will cause many autogenerated bindings to be regenerated perpetually
# until the result is actually different.
if newContents == oldFileContents:
return False
#oldFileContents = ""
#try:
# oldFile = open(filename, 'rb')
# oldFileContents = ''.join(oldFile.readlines())
# oldFile.close()
#except:
# pass
#if newContents == oldFileContents:
# return False
f = open(filename, 'wb')
f.write(newContents)
@ -91,6 +96,8 @@ class CastableObjectUnwrapper():
assert descriptor.castable
self.substitution = { "type" : descriptor.nativeType,
"depth": descriptor.interface.inheritanceDepth(),
"prototype": "prototypes::id::" + descriptor.name,
"protoID" : "prototypes::id::" + descriptor.name + " as uint",
"source" : source,
"target" : target,
@ -115,8 +122,14 @@ class CastableObjectUnwrapper():
def __str__(self):
return string.Template(
"""${target} = unwrap(${source});
"""match unwrap_object(${source}, ${prototype}, ${depth}) {
Ok(val) => ${target} = val,
Err(()) => {
${codeOnFailure}
}
}
""").substitute(self.substitution)
#"""{
# nsresult rv = UnwrapObject<${protoID}, ${type}>(cx, ${source}, ${target});
# if (NS_FAILED(rv)) {
@ -130,7 +143,7 @@ class FailureFatalCastableObjectUnwrapper(CastableObjectUnwrapper):
"""
def __init__(self, descriptor, source, target):
CastableObjectUnwrapper.__init__(self, descriptor, source, target,
"return Throw<%s>(cx, rv);" %
"return 0; //XXXjdm return Throw<%s>(cx, rv);" %
toStringBool(not descriptor.workers))
class CGThing():
@ -394,6 +407,10 @@ class FakeCastableDescriptor():
self.pointerType = descriptor.pointerType
self.name = descriptor.name
self.hasXPConnectImpls = descriptor.hasXPConnectImpls
class FakeInterface:
def inheritanceDepth(self):
return descriptor.interface.inheritanceDepth()
self.interface = FakeInterface()
def dictionaryHasSequenceMember(dictionary):
return (any(typeIsSequenceOrHasSequenceMember(m.type) for m in
@ -543,7 +560,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None,
CGIndenter(CGGeneric(templateBody)).define() + "\n")
if type.nullable():
templateBody += (
"} else if (${val}.isNullOrUndefined()) {\n"
"} else if RUST_JSVAL_IS_NULL(${val}) != 0 || RUST_JSVAL_IS_VOID(${val}) != 0 {\n"
" %s;\n" % codeToSetNull)
templateBody += (
"} else {\n" +
@ -878,7 +895,7 @@ for (uint32_t i = 0; i < length; ++i) {
not descriptor.workers) or isMember
typeName = descriptor.nativeType
typePtr = typeName + "*"
typePtr = descriptor.pointerType + typeName
# Compute a few things:
# - declType is the type we want to return as the first element of our
@ -889,15 +906,9 @@ for (uint32_t i = 0; i < length; ++i) {
# Set up some sensible defaults for these things insofar as we can.
holderType = None
if argIsPointer:
if forceOwningType:
declType = "nsRefPtr<" + typeName + ">"
else:
declType = typePtr
declType = "Option<" + typePtr + ">"
else:
if forceOwningType:
declType = "OwningNonNull<" + typeName + ">"
else:
declType = descriptor.pointerType + typeName
declType = typePtr
templateBody = ""
if descriptor.castable:
@ -931,41 +942,19 @@ for (uint32_t i = 0; i < length; ++i) {
elif descriptor.workers:
templateBody += "${declName} = &${val}.toObject();"
else:
# Either external, or new-binding non-castable. We always have a
# holder for these, because we don't actually know whether we have
# to addref when unwrapping or not. So we just pass an
# getter_AddRefs(nsRefPtr) to XPConnect and if we'll need a release
# it'll put a non-null pointer in there.
if forceOwningType:
# Don't return a holderType in this case; our declName
# will just own stuff.
templateBody += "nsRefPtr<" + typeName + "> ${holderName};\n"
else:
holderType = "nsRefPtr<" + typeName + ">"
templateBody += (
"jsval tmpVal = ${val};\n" +
typePtr + " tmp;\n"
"if (NS_FAILED(xpc_qsUnwrapArg<" + typeName + ">(cx, ${val}, &tmp, static_cast<" + typeName + "**>(getter_AddRefs(${holderName})), &tmpVal))) {\n")
"match unwrap_value::<" + typePtr + ">(&${val} as *JSVal, "
"prototypes::id::%s, %d) {\n" % (descriptor.name, descriptor.interface.inheritanceDepth() if descriptor.concrete else 0) +
" Err(()) => {")
templateBody += CGIndenter(onFailureBadType(failureCode,
descriptor.interface.identifier.name)).define()
templateBody += ("}\n"
"MOZ_ASSERT(tmp);\n")
if not isDefinitelyObject:
# Our tmpVal will go out of scope, so we can't rely on it
# for rooting
templateBody += (
"if (tmpVal != ${val} && !${holderName}) {\n"
" // We have to have a strong ref, because we got this off\n"
" // some random object that might get GCed\n"
" ${holderName} = tmp;\n"
"}\n")
# And store our tmp, before it goes out of scope.
templateBody += "${declName} = tmp;"
templateBody += (
" }\n"
" Ok(unwrapped) => ${declName} = Some(unwrapped)\n"
"}\n")
templateBody = wrapObjectTemplate(templateBody, isDefinitelyObject,
type, "${declName} = NULL",
type, "${declName} = None",
failureCode)
declType = CGGeneric(declType)
@ -1305,10 +1294,15 @@ def instantiateJSToNativeConversionTemplate(templateTuple, replacements,
(holderType.define(), originalHolderName))
mutableHolderType = CGWrapper(holderType, pre="Optional< ", post=" >")
holderType = CGWrapper(mutableHolderType, pre="const ")
result.append(
CGList([holderType, CGGeneric(" "),
CGGeneric(originalHolderName),
CGGeneric(";")]))
tmpresult = [CGGeneric("let "),
CGGeneric(originalHolderName),
CGGeneric(": "),
holderType]
if initialValue:
tmpresult += [CGGeneric(" = "),
initialValue]
tmpresult += [CGGeneric(";")]
result.append(CGList(tmpresult))
originalDeclName = replacements["declName"]
if declType is not None:
@ -2073,7 +2067,7 @@ class CGNativePropertyHooks(CGThing):
parentHooks = ("&" + toBindingNamespace(parent.identifier.name) + "::NativeHooks"
if parent else '0 as *NativePropertyHooks')
return """
static NativeHooks: NativePropertyHooks = NativePropertyHooks { resolve_own_property: /*%s*/ 0 as *u8, resolve_property: ResolveProperty, enumerate_own_properties: /*%s*/ 0 as *u8, enumerate_properties: /*EnumerateProperties*/ 0 as *u8, proto_hooks: %s };
static NativeHooks: NativePropertyHooks = NativePropertyHooks { resolve_own_property: /*%s*/ 0 as *u8, resolve_property: ResolveProperty, enumerate_own_properties: /*%s*/ 0 as *u8, enumerate_properties: /*EnumerateProperties*/ 0 as *u8, proto_hooks: /*%s*/ 0 as *NativePropertyHooks };
""" % (resolveOwnProperty, enumerateOwnProperties, parentHooks)
# We'll want to insert the indent at the beginnings of lines, but we
@ -2729,11 +2723,11 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
A method for getting a per-interface object (a prototype object or interface
constructor object).
"""
def __init__(self, descriptor, name, idPrefix=""):
def __init__(self, descriptor, name, idPrefix="", pub=False):
args = [Argument('*JSContext', 'aCx'), Argument('*JSObject', 'aGlobal'),
Argument('*JSObject', 'aReceiver')]
CGAbstractMethod.__init__(self, descriptor, name,
'*JSObject', args, inline=True)
'*JSObject', args, inline=True, pub=pub)
self.id = idPrefix + "id::" + self.descriptor.name
def definition_body(self):
return """
@ -2765,7 +2759,7 @@ class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
"""
def __init__(self, descriptor):
CGGetPerInterfaceObject.__init__(self, descriptor, "GetProtoObject",
"prototypes::")
"prototypes::", pub=True)
def definition_body(self):
return """
/* Get the interface prototype object for this class. This will create the
@ -2846,7 +2840,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
getPrototypeOf: ptr::null()
};
(*script_context).dom_static.proxy_handlers.insert(prototypes::id::%s as uint,
CreateProxyHandler(ptr::to_unsafe_ptr(&traps)));
CreateProxyHandler(ptr::to_unsafe_ptr(&traps), ptr::to_unsafe_ptr(&Class) as *libc::c_void));
""" % self.descriptor.name
else:
@ -3107,6 +3101,25 @@ class FakeArgument():
self.enforceRange = False
self.clamp = False
class CGSetterCall(CGPerSignatureCall):
"""
A class to generate a native object setter call for a particular IDL
setter.
"""
def __init__(self, argType, nativeMethodName, descriptor, attr):
CGPerSignatureCall.__init__(self, None, [],
[FakeArgument(argType, attr)],
nativeMethodName, False, descriptor, attr,
setter=True)
def wrap_return_value(self):
# We have no return value
return "\nreturn 1;"
def getArgc(self):
return "1"
def getArgvDecl(self):
# We just get our stuff from our last arg no matter what
return ""
class CGAbstractBindingMethod(CGAbstractExternMethod):
"""
Common class to generate the JSNatives for all our methods, getters, and
@ -3119,7 +3132,7 @@ class CGAbstractBindingMethod(CGAbstractExternMethod):
CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
if unwrapFailureCode is None:
self.unwrapFailureCode = ("return Throw<%s>(cx, rv);" %
self.unwrapFailureCode = ("return 0; //XXXjdm return Throw<%s>(cx, rv);" %
toStringBool(not descriptor.workers))
else:
self.unwrapFailureCode = unwrapFailureCode
@ -3138,7 +3151,7 @@ class CGAbstractBindingMethod(CGAbstractExternMethod):
def getThis(self):
return CGIndenter(
CGGeneric("let obj: *JSObject = JS_THIS_OBJECT(cx, vp);\n"
CGGeneric("let obj: *JSObject = JS_THIS_OBJECT(cx, cast::transmute(vp));\n"
"if obj.is_null() {\n"
" return false as JSBool;\n"
"}\n"
@ -3248,6 +3261,56 @@ class CGSpecializedGetter(CGAbstractExternMethod):
self.descriptor, self.attr)),
pre=" let obj = (*obj.unnamed);\n").define()
class CGGenericSetter(CGAbstractBindingMethod):
"""
A class for generating the Rust code for an IDL attribute setter.
"""
def __init__(self, descriptor, lenientThis=False):
args = [Argument('*JSContext', 'cx'), Argument('uint', 'argc'),
Argument('*mut JSVal', 'vp')]
if lenientThis:
name = "genericLenientSetter"
unwrapFailureCode = (
"MOZ_ASSERT(!JS_IsExceptionPending(cx));\n"
"return true;")
else:
name = "genericSetter"
unwrapFailureCode = None
CGAbstractBindingMethod.__init__(self, descriptor, name, args,
unwrapFailureCode)
def generate_code(self):
return CGIndenter(CGGeneric(
"let undef = JSVAL_VOID;\n"
"let argv: *JSVal = if argc != 0 { JS_ARGV(cx, cast::transmute(vp)) } else { &undef as *JSVal };\n"
"let info: *JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, cast::transmute(vp)));\n"
"if CallJitPropertyOp(info, cx, obj, ptr::to_unsafe_ptr(&(*this).payload) as *libc::c_void, cast::transmute(vp)) == 0 {"
" return 0;\n"
"}\n"
"*vp = JSVAL_VOID;\n"
"return 1;"))
class CGSpecializedSetter(CGAbstractExternMethod):
"""
A class for generating the code for a specialized attribute setter
that the JIT can call with lower overhead.
"""
def __init__(self, descriptor, attr):
self.attr = attr
name = 'set_' + attr.identifier.name
args = [ Argument('*JSContext', 'cx'),
Argument('JSHandleObject', 'obj'),
Argument('*mut %s' % descriptor.nativeType, 'this'),
Argument('*mut JSVal', 'argv')]
CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
def definition_body(self):
name = self.attr.identifier.name
nativeName = "Set" + MakeNativeName(self.descriptor.binaryNames.get(name, name))
return CGWrapper(CGIndenter(CGSetterCall(self.attr.type, nativeName,
self.descriptor, self.attr)),
pre=" let obj = (*obj.unnamed);\n").define()
def infallibleForMember(member, type, descriptorProvider):
"""
Determine the fallibility of changing a C++ value of IDL type "type" into
@ -3786,7 +3849,7 @@ class CGDescriptor(CGThing):
else:
hasGetter = True
if not m.readonly:
#cgThings.append(CGSpecializedSetter(descriptor, m))
cgThings.append(CGSpecializedSetter(descriptor, m))
if m.hasLenientThis():
hasLenientSetter = True
else:
@ -3796,7 +3859,7 @@ class CGDescriptor(CGThing):
if hasGetter: cgThings.append(CGGenericGetter(descriptor))
#if hasLenientGetter: cgThings.append(CGGenericGetter(descriptor,
# lenientThis=True))
#if hasSetter: cgThings.append(CGGenericSetter(descriptor))
if hasSetter: cgThings.append(CGGenericSetter(descriptor))
#if hasLenientSetter: cgThings.append(CGGenericSetter(descriptor,
# lenientThis=True))
@ -3926,7 +3989,8 @@ class CGDictionary(CGThing):
return ""
d = self.dictionary
if d.parent:
inheritance = ": public %s " % self.makeClassName(d.parent) #XXXjdm
inheritance = " parent: %s::%s,\n" % (self.makeModuleName(d.parent),
self.makeClassName(d.parent))
else:
inheritance = ""
memberDecls = [" %s: %s," %
@ -3934,7 +3998,8 @@ class CGDictionary(CGThing):
for m in self.memberInfo]
return (string.Template(
"pub struct ${selfName} {\n" + #XXXjdm deal with inheritance
"pub struct ${selfName} {\n" +
"${inheritance}" +
"\n".join(memberDecls) + "\n" +
# NOTE: jsids are per-runtime, so don't use them in workers
"\n".join(" //static jsid " +
@ -3949,13 +4014,13 @@ class CGDictionary(CGThing):
d = self.dictionary
if d.parent:
initParent = ("// Per spec, we init the parent's members first\n"
"if (!%s::Init(cx, val)) {\n"
" return false;\n"
"}\n" % self.makeClassName(d.parent))
"if self.parent.Init(cx, val) == 0 {\n"
" return 0;\n"
"}\n")
else:
initParent = ""
memberInits = [CGIndenter(self.getMemberConversion(m)).define()
memberInits = [CGIndenter(self.getMemberConversion(m), indentLevel=6).define()
for m in self.memberInfo]
idinit = [CGGeneric('!InternJSString(cx, %s, "%s")' %
(m.identifier.name + "_id", m.identifier.name))
@ -3970,11 +4035,11 @@ class CGDictionary(CGThing):
def defaultValue(ty):
if ty is "bool":
return "false"
elif ty in ["i32", "u32"]:
elif ty in ["i32", "u32", "i16", "u16"]:
return "0"
elif ty is "nsString":
return "\"\""
elif ty.startswith("Optional"):
elif ty.startswith("Option"):
return "None"
else:
return "/* uh oh: %s */" % ty
@ -3987,42 +4052,43 @@ class CGDictionary(CGThing):
for m in d.members) + "\n"
"\n"
"impl ${selfName} {\n"
"fn new() -> ${selfName} {\n"
" ${selfName} {\n" +
"\n".join(" %s: %s," % (m[0].identifier.name, defaultValue(self.getMemberType(m))) for m in self.memberInfo) + "\n"
" pub fn new() -> ${selfName} {\n"
" ${selfName} {\n" +
((" parent: %s::%s::new(),\n" % (self.makeModuleName(d.parent),
self.makeClassName(d.parent))) if d.parent else "") +
"\n".join(" %s: %s," % (m[0].identifier.name, defaultValue(self.getMemberType(m))) for m in self.memberInfo) + "\n"
" }\n"
" }\n"
"}\n"
"\n"
"fn InitIds(cx: *JSContext) -> bool {\n"
" //MOZ_ASSERT(!initedIds);\n"
"/*${idInit}\n"
" initedIds = true;*/ //XXXjdm\n"
" return true;\n"
"}\n"
" pub fn InitIds(&mut self, cx: *JSContext) -> bool {\n"
" //MOZ_ASSERT(!initedIds);\n"
" /*${idInit}\n"
" initedIds = true;*/ //XXXjdm\n"
" return true;\n"
" }\n"
"\n" if not self.workers else "") +
"fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool\n"
"{\n"
" unsafe {\n" +
" pub fn Init(&mut self, cx: *JSContext, val: JSVal) -> JSBool {\n"
" unsafe {\n" +
# NOTE: jsids are per-runtime, so don't use them in workers
(" if (!initedIds && !${selfName}::InitIds(cx)) {\n"
" return 0;\n"
" }\n" if not self.workers else "") +
(" if (!initedIds && !self.InitIds(cx)) {\n"
" return 0;\n"
" }\n" if not self.workers else "") +
"${initParent}"
" let mut found: JSBool = 0;\n"
" let temp: JSVal = JSVAL_NULL;\n"
" let isNull = RUST_JSVAL_IS_NULL(val) != 0 || RUST_JSVAL_IS_VOID(val) != 0;\n"
" if !isNull && RUST_JSVAL_IS_PRIMITIVE(val) != 0 {\n"
" return 0; //XXXjdm throw properly here\n"
" //return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
" }\n"
" let mut found: JSBool = 0;\n"
" let temp: JSVal = JSVAL_NULL;\n"
" let isNull = RUST_JSVAL_IS_NULL(val) != 0 || RUST_JSVAL_IS_VOID(val) != 0;\n"
" if !isNull && RUST_JSVAL_IS_PRIMITIVE(val) != 0 {\n"
" return 0; //XXXjdm throw properly here\n"
" //return Throw<${isMainThread}>(cx, NS_ERROR_XPC_BAD_CONVERT_JS);\n"
" }\n"
"\n"
"${initMembers}\n"
" return 1;\n"
" return 1;\n"
" }\n"
" }\n"
"}\n"
"}").substitute({
"selfName": self.makeClassName(d),
"initParent": CGIndenter(CGGeneric(initParent)).define(),
"initParent": CGIndenter(CGGeneric(initParent), indentLevel=6).define(),
"initMembers": "\n\n".join(memberInits),
"idInit": CGIndenter(idinit).define(),
"isMainThread": toStringBool(not self.workers)
@ -4036,6 +4102,15 @@ class CGDictionary(CGThing):
def makeClassName(self, dictionary):
return self.makeDictionaryName(dictionary, self.workers)
@staticmethod
def makeModuleName(dictionary):
name = dictionary.identifier.name
if name.endswith('Init'):
return toBindingNamespace(name.replace('Init', ''))
#XXXjdm This breaks on the test webidl files, sigh.
#raise TypeError("No idea how to find this dictionary's definition: " + name)
return "/* uh oh */ %s" % name
def getMemberType(self, memberInfo):
(member, (templateBody, declType,
holderType, dealWithOptional, initialValue)) = memberInfo
@ -4209,6 +4284,10 @@ class CGBindingRoot(CGThing):
'dom::event::*', #XXXjdm
'dom::eventtarget::*', #XXXjdm
'dom::formdata::*', #XXXjdm
'dom::mouseevent::*', #XXXjdm
'dom::uievent::*', #XXXjdm
'dom::windowproxy::*', #XXXjdm
'dom::bindings::codegen::*', #XXXjdm
'script_task::task_from_context',
'dom::bindings::utils::EnumEntry',
'dom::node::ScriptView',