Skip to content

Commit

Permalink
auto merge of #4449 : Ms2ger/servo/unwrap_jsmanaged, r=jdm
Browse files Browse the repository at this point in the history
  • Loading branch information
bors-servo committed Dec 20, 2014
2 parents 58e7b8c + 96180ec commit 8a4eea0
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 130 deletions.
20 changes: 9 additions & 11 deletions components/script/dom/bindings/codegen/CodegenRust.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,13 @@ class CastableObjectUnwrapper():
"""
def __init__(self, descriptor, source, codeOnFailure):
self.substitution = {
"type": descriptor.nativeType,
"depth": descriptor.interface.inheritanceDepth(),
"prototype": "PrototypeList::ID::" + descriptor.name,
"protoID": "PrototypeList::ID::" + descriptor.name + " as uint",
"source": source,
"codeOnFailure": CGIndenter(CGGeneric(codeOnFailure), 4).define(),
}

def __str__(self):
return string.Template(
"""match unwrap_jsmanaged(${source}, ${prototype}, ${depth}) {
"""match unwrap_jsmanaged(${source}) {
Ok(val) => val,
Err(()) => {
${codeOnFailure}
Expand Down Expand Up @@ -1669,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',
Expand Down Expand Up @@ -3926,10 +3922,10 @@ def generate_code(self):
assert(False)

def finalizeHook(descriptor, hookName, context):
release = """let val = JS_GetReservedSlot(obj, dom_object_slot(obj));
let _: Box<%s> = mem::transmute(val.to_private());
release = """let value = unwrap::<%s>(obj);
let _: Box<%s> = mem::transmute(value);
debug!("%s finalize: {:p}", this);
""" % (descriptor.concreteType, descriptor.concreteType)
""" % (descriptor.concreteType, descriptor.concreteType, descriptor.concreteType)
return release

class CGClassTraceHook(CGAbstractClassHook):
Expand Down Expand Up @@ -4496,14 +4492,14 @@ def __init__(self, config, prefix, webIDLFile):
'dom::bindings::js::{OptionalRootedReference, OptionalOptionalRootedRootable}',
'dom::bindings::utils::{CreateDOMGlobal, CreateInterfaceObjects2}',
'dom::bindings::utils::ConstantSpec',
'dom::bindings::utils::{dom_object_slot, 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}',
Expand All @@ -4512,6 +4508,8 @@ def __init__(self, config, prefix, webIDLFile):
'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}',
Expand Down
119 changes: 114 additions & 5 deletions components/script/dom/bindings/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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};
Expand Down Expand Up @@ -345,14 +346,122 @@ 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<T>(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<DOMClass, ()> {
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<T>` 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<T>(mut obj: *mut JSObject) -> Result<JS<T>, ()>
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::<T>);
let proto_depth = IDLInterface::get_prototype_depth(None::<T>);
if dom_class.interface_chain[proto_depth] == proto_id {
debug!("good prototype");
Ok(JS::from_raw(unwrap(obj)))
} else {
debug!("bad prototype");
Err(())
}
}
}

impl<T: Reflectable+IDLInterface> FromJSValConvertible<()> for JS<T> {
fn from_jsval(_cx: *mut JSContext, value: JSVal, _option: ()) -> Result<JS<T>, ()> {
if !value.is_object() {
return Err(());
}
unwrap_jsmanaged(value.to_object(),
IDLInterface::get_prototype_id(None::<T>),
IDLInterface::get_prototype_depth(None::<T>))
unwrap_jsmanaged(value.to_object())
}
}

Expand Down
2 changes: 1 addition & 1 deletion components/script/dom/bindings/proxyhandler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down
115 changes: 4 additions & 111 deletions components/script/dom/bindings/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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};
Expand Down Expand Up @@ -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<T>(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<DOMClass, ()> {
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<T>` 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<T: Reflectable>(mut obj: *mut JSObject,
proto_id: PrototypeList::ID,
proto_depth: uint) -> Result<JS<T>, ()> {
unsafe {
let dom_class = 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(())
}
});

dom_class.and_then(|dom_class| {
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<T>(x: Box<T>) -> *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.
Expand Down Expand Up @@ -650,12 +548,7 @@ pub extern fn outerize_global(_cx: *mut JSContext, obj: JSHandleObject) -> *mut
unsafe {
debug!("outerizing");
let obj = *obj.unnamed_field1;
let win: Root<window::Window> =
unwrap_jsmanaged(obj,
IDLInterface::get_prototype_id(None::<window::Window>),
IDLInterface::get_prototype_depth(None::<window::Window>))
.unwrap()
.root();
let win: Root<window::Window> = unwrap_jsmanaged(obj).unwrap().root();
win.browser_context().as_ref().unwrap().window_proxy()
}
}
Expand Down
Loading

0 comments on commit 8a4eea0

Please sign in to comment.