From 96180ec3adc855cfa32e92156d766986a1748e5a Mon Sep 17 00:00:00 2001 From: Ms2ger Date: Sat, 20 Dec 2014 14:51:14 +0100 Subject: [PATCH] Move unwrap_jsmanaged and related machinery to conversions.rs. --- .../dom/bindings/codegen/CodegenRust.py | 8 +- components/script/dom/bindings/conversions.rs | 115 +++++++++++++++++- .../script/dom/bindings/proxyhandler.rs | 2 +- components/script/dom/bindings/utils.rs | 108 +--------------- components/script/dom/node.rs | 4 +- 5 files changed, 124 insertions(+), 113 deletions(-) diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 7f6a5ba1ccb..d6692fc13cb 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -1665,10 +1665,10 @@ def UnionTypes(descriptors, dictionaries, callbacks, config): """ imports = [ - 'dom::bindings::utils::unwrap_jsmanaged', 'dom::bindings::codegen::PrototypeList', 'dom::bindings::conversions::FromJSValConvertible', 'dom::bindings::conversions::ToJSValConvertible', + 'dom::bindings::conversions::unwrap_jsmanaged', 'dom::bindings::conversions::StringificationBehavior::Default', 'dom::bindings::error::throw_not_in_union', 'dom::bindings::js::JS', @@ -4492,14 +4492,14 @@ class CGBindingRoot(CGThing): 'dom::bindings::js::{OptionalRootedReference, OptionalOptionalRootedRootable}', 'dom::bindings::utils::{CreateDOMGlobal, CreateInterfaceObjects2}', 'dom::bindings::utils::ConstantSpec', - 'dom::bindings::utils::{DOM_OBJECT_SLOT, DOMClass}', + 'dom::bindings::utils::{DOMClass}', 'dom::bindings::utils::{DOMJSClass, JSCLASS_DOM_GLOBAL}', 'dom::bindings::utils::{FindEnumStringIndex, GetArrayIndexFromId}', 'dom::bindings::utils::{GetPropertyOnPrototype, GetProtoOrIfaceArray}', 'dom::bindings::utils::HasPropertyOnPrototype', 'dom::bindings::utils::{Reflectable}', 'dom::bindings::utils::{squirrel_away_unique}', - 'dom::bindings::utils::{ThrowingConstructor, unwrap, unwrap_jsmanaged}', + 'dom::bindings::utils::{ThrowingConstructor}', 'dom::bindings::utils::get_dictionary_property', 'dom::bindings::utils::{NativeProperties, NativePropertyHooks}', 'dom::bindings::utils::ConstantVal::{IntVal, UintVal}', @@ -4508,6 +4508,8 @@ class CGBindingRoot(CGThing): 'dom::bindings::callback::{CallSetup,ExceptionHandling}', 'dom::bindings::callback::{WrapCallThisObject}', 'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}', + 'dom::bindings::conversions::{unwrap, unwrap_jsmanaged}', + 'dom::bindings::conversions::DOM_OBJECT_SLOT', 'dom::bindings::conversions::IDLInterface', 'dom::bindings::conversions::jsid_to_str', 'dom::bindings::conversions::StringificationBehavior::{Default, Empty}', diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs index ceac869a19e..88daa47a448 100644 --- a/components/script/dom/bindings/conversions.rs +++ b/components/script/dom/bindings/conversions.rs @@ -9,10 +9,10 @@ use dom::bindings::codegen::PrototypeList; use dom::bindings::js::{JS, JSRef, Root}; use dom::bindings::str::ByteString; -use dom::bindings::utils::{Reflectable, Reflector}; -use dom::bindings::utils::unwrap_jsmanaged; +use dom::bindings::utils::{Reflectable, Reflector, DOMClass}; use servo_util::str::DOMString; +use js; use js::glue::{RUST_JSID_TO_STRING, RUST_JSID_IS_STRING}; use js::glue::RUST_JS_NumberValue; use js::jsapi::{JSBool, JSContext, JSObject, JSString, jsid}; @@ -22,6 +22,7 @@ use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean}; use js::jsapi::{JS_ValueToString, JS_GetStringCharsAndLength}; use js::jsapi::{JS_NewUCStringCopyN, JS_NewStringCopyN}; use js::jsapi::{JS_WrapValue}; +use js::jsapi::{JSClass, JS_GetClass}; use js::jsval::JSVal; use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value}; use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue}; @@ -345,6 +346,116 @@ impl ToJSValConvertible for Reflector { } } +/// Returns whether the given `clasp` is one for a DOM object. +fn is_dom_class(clasp: *const JSClass) -> bool { + unsafe { + ((*clasp).flags & js::JSCLASS_IS_DOMJSCLASS) != 0 + } +} + +/// Returns whether `obj` is a DOM object implemented as a proxy. +pub fn is_dom_proxy(obj: *mut JSObject) -> bool { + use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFamily}; + + unsafe { + (js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) && + IsProxyHandlerFamily(obj) + } +} + +/// The index of the slot wherein a pointer to the reflected DOM object is +/// stored for non-proxy bindings. +// We use slot 0 for holding the raw object. This is safe for both +// globals and non-globals. +pub const DOM_OBJECT_SLOT: uint = 0; +const DOM_PROXY_OBJECT_SLOT: uint = js::JSSLOT_PROXY_PRIVATE as uint; + +/// Returns the index of the slot wherein a pointer to the reflected DOM object +/// is stored. +/// +/// Fails if `obj` is not a DOM object. +pub unsafe fn dom_object_slot(obj: *mut JSObject) -> u32 { + let clasp = JS_GetClass(obj); + if is_dom_class(&*clasp) { + DOM_OBJECT_SLOT as u32 + } else { + assert!(is_dom_proxy(obj)); + DOM_PROXY_OBJECT_SLOT as u32 + } +} + +/// Get the DOM object from the given reflector. +pub unsafe fn unwrap(obj: *mut JSObject) -> *const T { + use js::jsapi::JS_GetReservedSlot; + + let slot = dom_object_slot(obj); + let value = JS_GetReservedSlot(obj, slot); + value.to_private() as *const T +} + +/// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object. +unsafe fn get_dom_class(obj: *mut JSObject) -> Result { + use dom::bindings::utils::DOMJSClass; + use js::glue::GetProxyHandlerExtra; + + let clasp = JS_GetClass(obj); + if is_dom_class(&*clasp) { + debug!("plain old dom object"); + let domjsclass: *const DOMJSClass = clasp as *const DOMJSClass; + return Ok((*domjsclass).dom_class); + } + if is_dom_proxy(obj) { + debug!("proxy dom object"); + let dom_class: *const DOMClass = GetProxyHandlerExtra(obj) as *const DOMClass; + return Ok(*dom_class); + } + debug!("not a dom object"); + return Err(()); +} + +/// Get a `JS` for the given DOM object, unwrapping any wrapper around it +/// first, and checking if the object is of the correct type. +/// +/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is +/// not a reflector for a DOM object of the given type (as defined by the +/// proto_id and proto_depth). +pub fn unwrap_jsmanaged(mut obj: *mut JSObject) -> Result, ()> + where T: Reflectable + IDLInterface +{ + use js::glue::{IsWrapper, UnwrapObject}; + use std::ptr; + + unsafe { + let dom_class = try!(get_dom_class(obj).or_else(|_| { + if IsWrapper(obj) == 1 { + debug!("found wrapper"); + obj = UnwrapObject(obj, /* stopAtOuter = */ 0, ptr::null_mut()); + if obj.is_null() { + debug!("unwrapping security wrapper failed"); + Err(()) + } else { + assert!(IsWrapper(obj) == 0); + debug!("unwrapped successfully"); + get_dom_class(obj) + } + } else { + debug!("not a dom wrapper"); + Err(()) + } + })); + + let proto_id = IDLInterface::get_prototype_id(None::); + let proto_depth = IDLInterface::get_prototype_depth(None::); + if dom_class.interface_chain[proto_depth] == proto_id { + debug!("good prototype"); + Ok(JS::from_raw(unwrap(obj))) + } else { + debug!("bad prototype"); + Err(()) + } + } +} + impl FromJSValConvertible<()> for JS { fn from_jsval(_cx: *mut JSContext, value: JSVal, _option: ()) -> Result, ()> { if !value.is_object() { diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs index 3321c1f617f..d6a4726ba4d 100644 --- a/components/script/dom/bindings/proxyhandler.rs +++ b/components/script/dom/bindings/proxyhandler.rs @@ -4,8 +4,8 @@ ///! Utilities for the implementation of JSAPI proxy handlers. +use dom::bindings::conversions::is_dom_proxy; use dom::bindings::utils::delete_property_by_id; -use dom::bindings::utils::is_dom_proxy; use js::jsapi::{JSContext, jsid, JSPropertyDescriptor, JSObject, JSString, jschar}; use js::jsapi::{JS_GetPropertyDescriptorById, JS_NewUCString, JS_malloc, JS_free}; use js::jsapi::{JS_DefinePropertyById, JS_NewObjectWithGivenProto}; diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 048a54eee4a..19e87bf6a5e 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -8,10 +8,10 @@ use dom::bindings::codegen::PrototypeList; use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH; -use dom::bindings::conversions::IDLInterface; +use dom::bindings::conversions::unwrap_jsmanaged; use dom::bindings::error::throw_type_error; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{JS, Temporary, Root}; +use dom::bindings::js::{Temporary, Root}; use dom::browsercontext; use dom::window; @@ -20,9 +20,7 @@ use libc::c_uint; use std::cell::Cell; use std::mem; use std::ptr; -use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFamily}; -use js::glue::{UnwrapObject, GetProxyHandlerExtra}; -use js::glue::{IsWrapper, RUST_JSID_IS_INT, RUST_JSID_TO_INT}; +use js::glue::{RUST_JSID_IS_INT, RUST_JSID_TO_INT}; use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewFunction}; use js::jsapi::{JS_DefineProperties, JS_ForwardGetPropertyTo}; use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype, JS_GetStringCharsAndLength}; @@ -64,111 +62,11 @@ pub fn GlobalStaticData() -> GlobalStaticData { } } -/// Returns whether the given `clasp` is one for a DOM object. -fn is_dom_class(clasp: *const JSClass) -> bool { - unsafe { - ((*clasp).flags & js::JSCLASS_IS_DOMJSCLASS) != 0 - } -} - -/// Returns whether `obj` is a DOM object implemented as a proxy. -pub fn is_dom_proxy(obj: *mut JSObject) -> bool { - unsafe { - (js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) && - IsProxyHandlerFamily(obj) - } -} - -/// Returns the index of the slot wherein a pointer to the reflected DOM object -/// is stored. -/// -/// Fails if `obj` is not a DOM object. -pub unsafe fn dom_object_slot(obj: *mut JSObject) -> u32 { - let clasp = JS_GetClass(obj); - if is_dom_class(&*clasp) { - DOM_OBJECT_SLOT as u32 - } else { - assert!(is_dom_proxy(obj)); - DOM_PROXY_OBJECT_SLOT as u32 - } -} - -/// Get the DOM object from the given reflector. -pub unsafe fn unwrap(obj: *mut JSObject) -> *const T { - let slot = dom_object_slot(obj); - let val = JS_GetReservedSlot(obj, slot); - val.to_private() as *const T -} - -/// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object. -pub unsafe fn get_dom_class(obj: *mut JSObject) -> Result { - let clasp = JS_GetClass(obj); - if is_dom_class(&*clasp) { - debug!("plain old dom object"); - let domjsclass: *const DOMJSClass = clasp as *const DOMJSClass; - return Ok((*domjsclass).dom_class); - } - if is_dom_proxy(obj) { - debug!("proxy dom object"); - let dom_class: *const DOMClass = GetProxyHandlerExtra(obj) as *const DOMClass; - return Ok(*dom_class); - } - debug!("not a dom object"); - return Err(()); -} - -/// Get a `JS` for the given DOM object, unwrapping any wrapper around it -/// first, and checking if the object is of the correct type. -/// -/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is -/// not a reflector for a DOM object of the given type (as defined by the -/// proto_id and proto_depth). -pub fn unwrap_jsmanaged(mut obj: *mut JSObject) -> Result, ()> - where T: Reflectable + IDLInterface -{ - unsafe { - let dom_class = try!(get_dom_class(obj).or_else(|_| { - if IsWrapper(obj) == 1 { - debug!("found wrapper"); - obj = UnwrapObject(obj, /* stopAtOuter = */ 0, ptr::null_mut()); - if obj.is_null() { - debug!("unwrapping security wrapper failed"); - Err(()) - } else { - assert!(IsWrapper(obj) == 0); - debug!("unwrapped successfully"); - get_dom_class(obj) - } - } else { - debug!("not a dom wrapper"); - Err(()) - } - })); - - let proto_id = IDLInterface::get_prototype_id(None::); - let proto_depth = IDLInterface::get_prototype_depth(None::); - if dom_class.interface_chain[proto_depth] == proto_id { - debug!("good prototype"); - Ok(JS::from_raw(unwrap(obj))) - } else { - debug!("bad prototype"); - Err(()) - } - } -} - /// Leak the given pointer. pub unsafe fn squirrel_away_unique(x: Box) -> *const T { mem::transmute(x) } -/// The index of the slot wherein a pointer to the reflected DOM object is -/// stored for non-proxy bindings. -// We use slot 0 for holding the raw object. This is safe for both -// globals and non-globals. -pub const DOM_OBJECT_SLOT: uint = 0; -const DOM_PROXY_OBJECT_SLOT: uint = js::JSSLOT_PROXY_PRIVATE as uint; - // NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and // LSetDOMProperty. Those constants need to be changed accordingly if this value // changes. diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index e8d6035e856..1584ff112ac 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -19,6 +19,7 @@ use dom::bindings::codegen::InheritTypes::{CharacterDataCast, NodeBase, NodeDeri use dom::bindings::codegen::InheritTypes::{ProcessingInstructionCast, EventTargetCast}; use dom::bindings::codegen::InheritTypes::{HTMLLegendElementDerived, HTMLFieldSetElementDerived}; use dom::bindings::codegen::InheritTypes::HTMLOptGroupElementDerived; +use dom::bindings::conversions; use dom::bindings::error::Fallible; use dom::bindings::error::Error::{NotFound, HierarchyRequest, Syntax}; use dom::bindings::global::GlobalRef; @@ -26,7 +27,6 @@ use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, Root}; use dom::bindings::js::{OptionalSettable, TemporaryPushable, OptionalRootedRootable}; use dom::bindings::js::{ResultRootable, OptionalRootable, MutNullableJS}; use dom::bindings::trace::JSTraceable; -use dom::bindings::utils; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::characterdata::CharacterData; use dom::comment::Comment; @@ -884,7 +884,7 @@ pub fn from_untrusted_node_address(runtime: *mut JSRuntime, candidate: Untrusted if object.is_null() { panic!("Attempted to create a `JS` from an invalid pointer!") } - let boxed_node: *const Node = utils::unwrap(object); + let boxed_node: *const Node = conversions::unwrap(object); Temporary::new(JS::from_raw(boxed_node)) } }