From 0d39bd1ba9bbc1e273cb68e27b3837a68eade2ef Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Wed, 10 Jul 2013 16:34:02 -0400 Subject: [PATCH] DOM bindings: Add support for fallible JS unwrapping. --- .../dom/bindings/codegen/CodegenRust.py | 58 ++++++++----------- src/components/script/dom/bindings/utils.rs | 51 +++++++++++++++- src/support/spidermonkey/rust-mozjs | 2 +- 3 files changed, 75 insertions(+), 36 deletions(-) diff --git a/src/components/script/dom/bindings/codegen/CodegenRust.py b/src/components/script/dom/bindings/codegen/CodegenRust.py index 5c9a0ab8726..8926674bd18 100644 --- a/src/components/script/dom/bindings/codegen/CodegenRust.py +++ b/src/components/script/dom/bindings/codegen/CodegenRust.py @@ -94,6 +94,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, @@ -118,8 +120,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)) { @@ -133,7 +141,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(): @@ -397,6 +405,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 @@ -934,41 +946,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) @@ -2849,7 +2839,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: @@ -3141,7 +3131,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 diff --git a/src/components/script/dom/bindings/utils.rs b/src/components/script/dom/bindings/utils.rs index 5fc2fcfc647..4a9d26ee36f 100644 --- a/src/components/script/dom/bindings/utils.rs +++ b/src/components/script/dom/bindings/utils.rs @@ -17,6 +17,7 @@ use std::uint; use std::unstable::intrinsics; use js::glue::*; use js::glue::{DefineFunctionWithReserved, GetObjectJSClass, RUST_OBJECT_TO_JSVAL}; +use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFamily}; use js::glue::{PROPERTY_STUB, STRICT_PROPERTY_STUB, ENUMERATE_STUB, CONVERT_STUB, RESOLVE_STUB}; use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewObject, JS_NewFunction}; use js::jsapi::{JS_DefineProperties, JS_WrapValue, JS_ForwardGetPropertyTo}; @@ -117,16 +118,62 @@ fn is_dom_class(clasp: *JSClass) -> bool { } } +fn is_dom_proxy(obj: *JSObject) -> bool { + unsafe { + (js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) && + IsProxyHandlerFamily(obj) + } +} + pub unsafe fn unwrap(obj: *JSObject) -> T { - let slot = if is_dom_class(JS_GetClass(obj)) { + let clasp = JS_GetClass(obj); + let slot = if is_dom_class(clasp) { DOM_OBJECT_SLOT } else { + assert!(is_dom_proxy(obj)); DOM_PROXY_OBJECT_SLOT } as u32; let val = JS_GetReservedSlot(obj, slot); cast::transmute(RUST_JSVAL_TO_PRIVATE(val)) } +pub unsafe fn get_dom_class(obj: *JSObject) -> Result { + let clasp = JS_GetClass(obj); + if is_dom_class(clasp) { + debug!("plain old dom object"); + let domjsclass: *DOMJSClass = cast::transmute(clasp); + return Ok((*domjsclass).dom_class); + } + if is_dom_proxy(obj) { + debug!("proxy dom object"); + let dom_class: *DOMClass = cast::transmute(GetProxyHandlerExtra(obj)); + return Ok(*dom_class); + } + debug!("not a dom object"); + return Err(()); +} + +pub fn unwrap_object(obj: *JSObject, proto_id: prototypes::id::Prototype, proto_depth: uint) -> Result { + unsafe { + do get_dom_class(obj).chain |dom_class| { + if dom_class.interface_chain[proto_depth] == proto_id { + debug!("good prototype"); + Ok(unwrap(obj)) + } else { + debug!("bad prototype"); + Err(()) + } + } + } +} + +pub fn unwrap_value(val: *JSVal, proto_id: prototypes::id::Prototype, proto_depth: uint) -> Result { + unsafe { + let obj = RUST_JSVAL_TO_OBJECT(*val); + unwrap_object(obj, proto_id, proto_depth) + } +} + pub unsafe fn squirrel_away(x: @mut T) -> *rust_box { let y: *rust_box = cast::transmute(x); cast::forget(x); @@ -373,7 +420,9 @@ pub fn GetProtoOrIfaceArray(global: *JSObject) -> **JSObject { pub mod prototypes { pub mod id { + #[deriving(Eq)] pub enum Prototype { + Blob, ClientRect, ClientRectList, DOMParser, diff --git a/src/support/spidermonkey/rust-mozjs b/src/support/spidermonkey/rust-mozjs index 26dc2e896a5..372622906d1 160000 --- a/src/support/spidermonkey/rust-mozjs +++ b/src/support/spidermonkey/rust-mozjs @@ -1 +1 @@ -Subproject commit 26dc2e896a57a28f03be43df46868e1a41a15807 +Subproject commit 372622906d112ae28825be1d5fcd8737cd03ae58