From 771d319168204e58b4c0c3d68a82a63259814d25 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 9 May 2014 17:08:11 -0400 Subject: [PATCH 01/12] Build with upgraded SpiderMonkey. --- Cargo.lock | 8 +- components/layout/wrapper.rs | 4 +- components/script/dom/bindings/callback.rs | 13 +- .../dom/bindings/codegen/CodegenRust.py | 617 +++++++++++------- components/script/dom/bindings/conversions.rs | 59 +- components/script/dom/bindings/error.rs | 22 +- components/script/dom/bindings/js.rs | 190 +++++- .../script/dom/bindings/proxyhandler.rs | 73 ++- components/script/dom/bindings/trace.rs | 94 ++- components/script/dom/bindings/utils.rs | 279 ++++---- components/script/dom/browsercontext.rs | 95 ++- .../script/dom/dedicatedworkerglobalscope.rs | 20 +- components/script/dom/document.rs | 29 +- components/script/dom/element.rs | 31 +- components/script/dom/event.rs | 17 +- components/script/dom/eventdispatcher.rs | 34 +- components/script/dom/eventtarget.rs | 38 +- components/script/dom/htmlimageelement.rs | 2 +- components/script/dom/mouseevent.rs | 9 +- components/script/dom/node.rs | 87 +-- components/script/dom/treewalker.rs | 4 +- components/script/dom/uievent.rs | 9 +- components/script/dom/window.rs | 42 +- components/script/dom/worker.rs | 25 +- components/script/dom/xmlhttprequest.rs | 20 +- components/script/html/hubbub_html_parser.rs | 2 + components/script/lib.rs | 13 + components/script/page.rs | 7 +- components/script/script_task.rs | 47 +- components/util/lib.rs | 2 +- ports/cef/Cargo.lock | 10 +- src/lib.rs | 6 +- tests/content/test_global.html | 1 + tests/content/test_interfaces.html | 4 + 34 files changed, 1241 insertions(+), 672 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e8f0abb8fe3..db3fb269c903 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,9 +257,9 @@ dependencies = [ [[package]] name = "js" version = "0.1.0" -source = "git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04" +source = "git+https://github.com/servo/rust-mozjs#750d714df96e2f5b810a2080e4c1a3c9c62d6985" dependencies = [ - "mozjs-sys 0.0.0 (git+https://github.com/servo/mozjs#47cd6a4e60c75642ba182f0df9a42b71ec7c2c88)", + "mozjs-sys 0.0.0 (git+https://github.com/servo/mozjs#526e23021805b26f8341e5e580b7ffbfc635d359)", ] [[package]] @@ -311,7 +311,7 @@ source = "git+https://github.com/Kimundi/lazy-static.rs#e62a65372f1dd9019e37eb93 [[package]] name = "mozjs-sys" version = "0.0.0" -source = "git+https://github.com/servo/mozjs#47cd6a4e60c75642ba182f0df9a42b71ec7c2c88" +source = "git+https://github.com/servo/mozjs#526e23021805b26f8341e5e580b7ffbfc635d359" [[package]] name = "msg" @@ -392,7 +392,7 @@ dependencies = [ "gfx 0.0.1", "http 0.1.0-pre (git+https://github.com/servo/rust-http?ref=servo#92019011b0cdf1bffc8c584830de1bf330d79d0d)", "hubbub 0.1.0 (git+https://github.com/servo/rust-hubbub#c7f868e688de6e9cbdc26aa09292ed072bc2648b)", - "js 0.1.0 (git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04)", + "js 0.1.0 (git+https://github.com/servo/rust-mozjs#750d714df96e2f5b810a2080e4c1a3c9c62d6985)", "msg 0.0.1", "net 0.0.1", "plugins 0.0.1", diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 4b4f3eef939a..7c0ad205a647 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -521,7 +521,7 @@ impl<'ln> TLayoutNode for ThreadSafeLayoutNode<'ln> { } unsafe fn get<'a>(&'a self) -> &'a Node { // this change. - mem::transmute::<*mut Node,&'a Node>(self.get_jsmanaged().unsafe_get()) + mem::transmute::<*const Node,&'a Node>(self.get_jsmanaged().unsafe_get()) } fn first_child(&self) -> Option> { @@ -619,7 +619,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> { // FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on // implementations. ThreadSafeLayoutElement { - element: &mut *element, + element: &*element, } } } diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs index d450dd25688d..897134265c31 100644 --- a/components/script/dom/bindings/callback.rs +++ b/components/script/dom/bindings/callback.rs @@ -7,7 +7,8 @@ use dom::bindings::global::global_object_for_js_object; use dom::bindings::js::JSRef; use dom::bindings::trace::Traceable; -use dom::bindings::utils::Reflectable; +use dom::bindings::utils::{Reflectable, object_handle}; +use dom::bindings::utils::{mut_value_handle, mut_object_handle}; use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable}; use js::jsapi::JS_GetProperty; use js::jsval::{JSVal, UndefinedValue}; @@ -100,12 +101,13 @@ impl CallbackInterface { let mut callable = UndefinedValue(); unsafe { let name = name.to_c_str(); - if JS_GetProperty(cx, self.callback(), name.as_ptr(), &mut callable) == 0 { + let callback = self.callback(); // XXX unrooted + if !JS_GetProperty(cx, object_handle(&callback), name.as_ptr(), mut_value_handle(&mut callable)) { return Err(()); } if !callable.is_object() || - JS_ObjectIsCallable(cx, callable.to_object()) == 0 { + !JS_ObjectIsCallable(cx, callable.to_object()) { // FIXME(#347) //ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get()); return Err(()); @@ -122,12 +124,11 @@ pub fn WrapCallThisObject(cx: *mut JSContext, assert!(obj.is_not_null()); unsafe { - if JS_WrapObject(cx, &mut obj) == 0 { + if !JS_WrapObject(cx, mut_object_handle(&mut obj)) { return ptr::null_mut(); } + return obj; } - - return obj; } /// A class that performs whatever setup we need to safely make a call while diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py index 5b0ee22fe7bf..38230242927b 100644 --- a/components/script/dom/bindings/codegen/CodegenRust.py +++ b/components/script/dom/bindings/codegen/CodegenRust.py @@ -199,7 +199,7 @@ def getPerSignatureCall(signature, argConversionStartsAt=0, signatureIndex=0): code = ( "if argc < %d {\n" " throw_type_error(cx, \"Not enough arguments to %s.\");\n" - " return 0;\n" + " return false;\n" "}" % (requiredArgs, methodName)) self.cgRoot.prepend( CGWrapper(CGGeneric(code), pre="\n", post="\n")) @@ -378,11 +378,11 @@ def pickFirstSignature(condition, filterLambda): CGSwitch("argcount", argCountCases, CGGeneric("throw_type_error(cx, \"Not enough arguments to %s.\");\n" - "return 0;\n" % methodName))) + "return false;\n" % methodName))) #XXXjdm Avoid unreachable statement warnings #overloadCGThings.append( # CGGeneric('fail!("We have an always-returning default case");\n' - # 'return 0;')) + # 'return false;')) self.cgRoot = CGWrapper(CGList(overloadCGThings, "\n"), pre="\n") @@ -499,7 +499,7 @@ def getJSToNativeConversionTemplate(type, descriptorProvider, failureCode=None, # failureCode will prevent pending exceptions from being set in cases when # they really should be! if exceptionCode is None: - exceptionCode = "return 0;" + exceptionCode = "return false;" needsRooting = typeNeedsRooting(type, descriptorProvider) @@ -723,7 +723,7 @@ def wrapObjectTemplate(templateBody, isDefinitelyObject, type, if invalidEnumValueFatal: handleInvalidEnumValueCode = exceptionCode else: - handleInvalidEnumValueCode = "return 1;" + handleInvalidEnumValueCode = "return true;" template = ( "match FindEnumStringIndex(cx, ${val}, %(values)s) {\n" @@ -817,7 +817,7 @@ def wrapObjectTemplate(templateBody, isDefinitelyObject, type, declType = CGGeneric(typeName) template = ("match %s::new(cx, ${val}) {\n" " Ok(dictionary) => dictionary,\n" - " Err(_) => return 0,\n" + " Err(_) => return false,\n" "}" % typeName) return handleOptional(template, declType, handleDefaultNull("%s::empty()" % typeName)) @@ -1007,7 +1007,7 @@ def define(self): return self.converter.define() -def wrapForType(jsvalRef, result='result', successCode='return 1;'): +def wrapForType(jsvalRef, result='result', successCode='return true;'): """ Reflect a Rust value into JS. @@ -1176,12 +1176,14 @@ def __init__(self, descriptor, name, static): for m in methods] # FIXME Check for an existing iterator on the interface first. - if any(m.isGetter() and m.isIndexed() for m in methods): - self.regular.append({"name": 'iterator', - "methodInfo": False, - "nativeName": "JS_ArrayIterator", - "length": 0, - "flags": "JSPROP_ENUMERATE" }) + #if any(m.isGetter() and m.isIndexed() for m in methods): + # self.regular.append({"name": '@@iterator', + # "methodInfo": False, + # "selfHostedName": "ArrayValues", + # "length": 0, + # "flags": "JSPROP_ENUMERATE", + #"condition": MemberCondition(None, None) + # "pref": None }) def generateArray(self, array, name): if len(array) == 0: @@ -1203,9 +1205,9 @@ def stringDecl(m): decls = ''.join([stringDecl(m) for m in array]) return decls + self.generatePrefableArray( array, name, - ' JSFunctionSpec {name: &%s_name as *const u8 as *const libc::c_char, call: JSNativeWrapper {op: Some(%s), info: %s}, nargs: %s, flags: %s as u16, selfHostedName: 0 as *const libc::c_char }', - ' JSFunctionSpec {name: 0 as *const libc::c_char, call: JSNativeWrapper {op: None, info: 0 as *const JSJitInfo}, nargs: 0, flags: 0, selfHostedName: 0 as *const libc::c_char }', - 'JSFunctionSpec', + ' Struct_JSFunctionSpec {name: &%s_name as *const u8 as *const libc::c_char, call: Struct_JSNativeWrapper {op: Some(%s), info: %s}, nargs: %s, flags: %s as u16, selfHostedName: 0 as *const libc::c_char }', + ' Struct_JSFunctionSpec {name: 0 as *const libc::c_char, call: Struct_JSNativeWrapper {op: None, info: 0 as *const JSJitInfo}, nargs: 0, flags: 0, selfHostedName: 0 as *const libc::c_char }', + 'Struct_JSFunctionSpec', specData) class AttrDefiner(PropertyDefiner): @@ -1237,13 +1239,13 @@ def getter(attr): accessor = "genericGetter" jitinfo = "&%s_getterinfo" % attr.identifier.name - return ("JSPropertyOpWrapper {op: Some(%(native)s), info: %(info)s as *const JSJitInfo}" + return ("Struct_JSNativeWrapper {op: Some(%(native)s), info: %(info)s as *const JSJitInfo}" % {"info" : jitinfo, "native" : accessor}) def setter(attr): if attr.readonly: - return "JSStrictPropertyOpWrapper {op: None, info: 0 as *const JSJitInfo}" + return "Struct_JSNativeWrapper {op: None, info: 0 as *const JSJitInfo}" if self.static: accessor = 'set_' + attr.identifier.name @@ -1255,7 +1257,7 @@ def setter(attr): accessor = "genericSetter" jitinfo = "&%s_setterinfo" % attr.identifier.name - return ("JSStrictPropertyOpWrapper {op: Some(%(native)s), info: %(info)s as *const JSJitInfo}" + return ("Struct_JSNativeWrapper {op: Some(%(native)s), info: %(info)s as *const JSJitInfo}" % {"info" : jitinfo, "native" : accessor}) @@ -1272,9 +1274,9 @@ def stringDecl(attr): return decls + self.generatePrefableArray( array, name, - ' JSPropertySpec { name: &%s_name as *const u8 as *const libc::c_char, tinyid: 0, flags: ((%s) & 0xFF) as u8, getter: %s, setter: %s }', - ' JSPropertySpec { name: 0 as *const libc::c_char, tinyid: 0, flags: 0, getter: JSPropertyOpWrapper {op: None, info: 0 as *const JSJitInfo}, setter: JSStrictPropertyOpWrapper {op: None, info: 0 as *const JSJitInfo} }', - 'JSPropertySpec', + ' Struct_JSPropertySpec { name: &%s_name as *const u8 as *const libc::c_char, flags: ((%s) & 0xFF) as u8, getter: %s, setter: %s }', + ' Struct_JSPropertySpec { name: 0 as *const libc::c_char, flags: 0, getter: Struct_JSNativeWrapper {op: None, info: 0 as *const JSJitInfo}, setter: Struct_JSNativeWrapper {op: None, info: 0 as *const JSJitInfo} }', + 'Struct_JSPropertySpec', specData) class ConstDefiner(PropertyDefiner): @@ -1436,9 +1438,11 @@ def __init__(self, descriptor): def define(self): traceHook = "Some(%s)" % TRACE_HOOK_NAME if self.descriptor.isGlobal(): + traceHook = "JS_GlobalObjectTraceHook" flags = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL" slots = "JSCLASS_GLOBAL_SLOT_COUNT + 1" else: + traceHook = TRACE_HOOK_NAME flags = "0" slots = "1" return """ @@ -1446,64 +1450,59 @@ def define(self): static Class: DOMJSClass = DOMJSClass { base: js::Class { name: &Class_name as *const u8 as *const libc::c_char, - flags: JSCLASS_IS_DOMJSCLASS | %s | (((%s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT as uint), //JSCLASS_HAS_RESERVED_SLOTS(%s), + flags: JSCLASS_IS_DOMJSCLASS | %s | (((%s) & JSCLASS_RESERVED_SLOTS_MASK as libc::c_uint) << JSCLASS_RESERVED_SLOTS_SHIFT as uint), //JSCLASS_HAS_RESERVED_SLOTS(%s), addProperty: Some(JS_PropertyStub), - delProperty: Some(JS_PropertyStub), + delProperty: Some(JS_DeletePropertyStub), getProperty: Some(JS_PropertyStub), setProperty: Some(JS_StrictPropertyStub), enumerate: Some(JS_EnumerateStub), resolve: Some(JS_ResolveStub), convert: Some(JS_ConvertStub), finalize: Some(%s), - checkAccess: None, call: None, hasInstance: None, construct: None, - trace: %s, + trace: Some(%s), + + spec: js::ClassSpec { + createConstructor: None, + createPrototype: None, + constructorFunctions: 0 as *const JSFunctionSpec, + prototypeFunctions: 0 as *const JSFunctionSpec, + finishInit: None, + }, ext: js::ClassExtension { - equality: 0 as *const u8, outerObject: %s, innerObject: None, iteratorObject: 0 as *const u8, - unused: 0 as *const u8, - isWrappedNative: 0 as *const u8, + isWrappedNative: false, + weakmapKeyDelegateOp: None, }, ops: js::ObjectOps { - lookupGeneric: 0 as *const u8, - lookupProperty: 0 as *const u8, - lookupElement: 0 as *const u8, - lookupSpecial: 0 as *const u8, - defineGeneric: 0 as *const u8, - defineProperty: 0 as *const u8, - defineElement: 0 as *const u8, - defineSpecial: 0 as *const u8, - getGeneric: 0 as *const u8, - getProperty: 0 as *const u8, - getElement: 0 as *const u8, - getElementIfPresent: 0 as *const u8, - getSpecial: 0 as *const u8, - setGeneric: 0 as *const u8, - setProperty: 0 as *const u8, - setElement: 0 as *const u8, - setSpecial: 0 as *const u8, - getGenericAttributes: 0 as *const u8, - getPropertyAttributes: 0 as *const u8, - getElementAttributes: 0 as *const u8, - getSpecialAttributes: 0 as *const u8, - setGenericAttributes: 0 as *const u8, - setPropertyAttributes: 0 as *const u8, - setElementAttributes: 0 as *const u8, - setSpecialAttributes: 0 as *const u8, - deleteProperty: 0 as *const u8, - deleteElement: 0 as *const u8, - deleteSpecial: 0 as *const u8, + lookupGeneric: None, + lookupProperty: None, + lookupElement: None, + defineGeneric: None, + defineProperty: None, + defineElement: None, + getGeneric: None, + getProperty: None, + getElement: None, + setGeneric: None, + setProperty: None, + setElement: None, + getGenericAttributes: None, + setGenericAttributes: None, + deleteProperty: None, + deleteElement: None, + watch: None, + unwatch: None, + slice: None, enumerate: 0 as *const u8, - typeOf: 0 as *const u8, thisObject: %s, - clear: 0 as *const u8, }, }, dom_class: %s @@ -1519,6 +1518,97 @@ def define(self): def str_to_const_array(s): return "[" + (", ".join(map(lambda x: "'" + x + "' as u8", list(s)) + ['0 as u8'])) + "]" + +class CGDOMProxyJSClass(CGThing): + """ + Generate a DOMJSClass for a given proxy descriptor + """ + def __init__(self, descriptor): + CGThing.__init__(self) + self.descriptor = descriptor + + def declare(self): + return "" + + def define(self): + flags = ["JSCLASS_IS_DOMJSCLASS", + "js::NON_NATIVE", + "js::JSCLASS_IS_PROXY", + "js::JSCLASS_IMPLEMENTS_BARRIERS", + "((js::PROXY_MINIMUM_SLOTS & js::JSCLASS_RESERVED_SLOTS_MASK as u32) << js::JSCLASS_RESERVED_SLOTS_SHIFT)"] + # We don't use an IDL annotation for JSCLASS_EMULATES_UNDEFINED because + # we don't want people ever adding that to any interface other than + # HTMLAllCollection. So just hardcode it here. + if self.descriptor.interface.identifier.name == "HTMLAllCollection": + flags.append("JSCLASS_EMULATES_UNDEFINED") + return """ +static Class_name: [u8, ..%i] = %s; +static mut Class: DOMJSClass = DOMJSClass { + base: js::Class { + name: &Class_name as *const u8 as *const libc::c_char, + flags: %s, + addProperty: Some(JS_PropertyStub), + delProperty: Some(JS_DeletePropertyStub), + getProperty: Some(JS_PropertyStub), + setProperty: Some(JS_StrictPropertyStub), + enumerate: Some(JS_EnumerateStub), + resolve: Some(JS_ResolveStub), + convert: Some(proxy_Convert), + finalize: Some(proxy_Finalize), + call: None, + hasInstance: Some(proxy_HasInstance), + construct: None, + trace: Some(proxy_Trace), + + spec: js::ClassSpec { + createConstructor: None, + createPrototype: None, + constructorFunctions: 0 as *const JSFunctionSpec, + prototypeFunctions: 0 as *const JSFunctionSpec, + finishInit: None, + }, + + ext: js::ClassExtension { + outerObject: None, + innerObject: Some(proxy_innerObject), + iteratorObject: 0 as *const u8, + isWrappedNative: false, + weakmapKeyDelegateOp: Some(proxy_WeakmapKeyDelegate), + }, + + ops: js::ObjectOps { + lookupGeneric: Some(proxy_LookupGeneric), + lookupProperty: Some(proxy_LookupProperty), + lookupElement: Some(proxy_LookupElement), + defineGeneric: Some(proxy_DefineGeneric), + defineProperty: Some(proxy_DefineProperty), + defineElement: Some(proxy_DefineElement), + getGeneric: Some(proxy_GetGeneric), + getProperty: Some(proxy_GetProperty), + getElement: Some(proxy_GetElement), + setGeneric: Some(proxy_SetGeneric), + setProperty: Some(proxy_SetProperty), + setElement: Some(proxy_SetElement), + getGenericAttributes: Some(proxy_GetGenericAttributes), + setGenericAttributes: Some(proxy_SetGenericAttributes), + deleteProperty: Some(proxy_DeleteProperty), + deleteElement: Some(proxy_DeleteElement), + watch: Some(proxy_Watch), + unwatch: Some(proxy_Unwatch), + slice: Some(proxy_Slice), + + enumerate: 0 as *const u8, + thisObject: None, + }, + }, + dom_class: %s +}; +""" % (len(self.descriptor.interface.identifier.name) + 1, + str_to_const_array(self.descriptor.interface.identifier.name), + " | ".join(flags), + CGIndenter(CGGeneric(DOMClass(self.descriptor))).define()) + + class CGPrototypeJSClass(CGThing): def __init__(self, descriptor): CGThing.__init__(self) @@ -1527,23 +1617,22 @@ def __init__(self, descriptor): def define(self): return """ static PrototypeClassName__: [u8, ..%s] = %s; -static PrototypeClass: JSClass = JSClass { +static PrototypeClass: JSClass = Struct_JSClass { name: &PrototypeClassName__ as *const u8 as *const libc::c_char, - flags: (1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT as uint, //JSCLASS_HAS_RESERVED_SLOTS(1) + flags: ((1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT) as libc::c_uint, //JSCLASS_HAS_RESERVED_SLOTS(1) addProperty: Some(JS_PropertyStub), - delProperty: Some(JS_PropertyStub), + delProperty: Some(JS_DeletePropertyStub), getProperty: Some(JS_PropertyStub), setProperty: Some(JS_StrictPropertyStub), enumerate: Some(JS_EnumerateStub), resolve: Some(JS_ResolveStub), convert: Some(JS_ConvertStub), finalize: None, - checkAccess: None, call: None, hasInstance: None, construct: None, trace: None, - reserved: [0 as *mut libc::c_void, ..40] + reserved: [0 as *mut libc::c_void, ..31] }; """ % (len(self.descriptor.interface.identifier.name + "Prototype") + 1, str_to_const_array(self.descriptor.interface.identifier.name + "Prototype")) @@ -1762,13 +1851,13 @@ def _decorators(self): if self.alwaysInline: decorators.append('#[inline(always)]') + if self.pub: + decorators.append('pub') + if self.extern: decorators.append('unsafe') decorators.append('extern') - if self.pub: - decorators.append('pub') - if not decorators: return '' return ' '.join(decorators) + ' ' @@ -1800,12 +1889,7 @@ def CreateBindingJSObject(descriptor, parent=None): create += """ let handler = RegisterBindings::proxy_handlers[PrototypeList::proxies::%s as uint]; let mut private = PrivateValue(squirrel_away_unique(aObject) as *const libc::c_void); -let obj = with_compartment(aCx, proto, || { - NewProxyObject(aCx, handler, - &private, - proto, %s, - ptr::null_mut(), ptr::null_mut()) -}); +let obj = NewProxyObject(aCx, handler, &mut Class.base, value_handle(&private), proto, %s); assert!(obj.is_not_null()); """ % (descriptor.name, parent) @@ -1813,9 +1897,7 @@ def CreateBindingJSObject(descriptor, parent=None): if descriptor.isGlobal(): create += "let obj = CreateDOMGlobal(aCx, &Class.base as *const js::Class as *const JSClass);\n" else: - create += ("let obj = with_compartment(aCx, proto, || {\n" - " JS_NewObject(aCx, &Class.base as *const js::Class as *const JSClass, &*proto, &*%s)\n" - "});\n" % parent) + create += ("let obj = JS_NewObject(aCx, &Class.base as *const js::Class as *const JSClass, object_handle(&proto), object_handle(&%s));\n" % parent) create += """assert!(obj.is_not_null()); JS_SetReservedSlot(obj, DOM_OBJECT_SLOT as u32, @@ -1842,11 +1924,13 @@ def __init__(self, descriptor): def definition_body(self): if not self.descriptor.isGlobal(): return CGGeneric("""\ -let scope = aScope.reflector().get_jsobject(); +let _ar = JSAutoRequest::new(aCx); +let mut scope = aScope.reflector().get_jsobject(); assert!(scope.is_not_null()); assert!(((*JS_GetClass(scope)).flags & JSCLASS_IS_GLOBAL) != 0); -let proto = with_compartment(aCx, scope, || GetProtoObject(aCx, scope, scope)); +let _ac = JSAutoCompartment::new(aCx, scope); +let mut proto = GetProtoObject(aCx, scope, scope); assert!(proto.is_not_null()); %s @@ -1856,15 +1940,16 @@ def definition_body(self): Temporary::new(raw)""" % CreateBindingJSObject(self.descriptor, "scope")) else: return CGGeneric("""\ +let _ar = JSAutoRequest::new(aCx); %s -with_compartment(aCx, obj, || { - let proto = GetProtoObject(aCx, obj, obj); - JS_SetPrototype(aCx, obj, proto); +let _ac = JSAutoCompartment::new(aCx, obj); + +let proto = GetProtoObject(aCx, obj, obj); +JS_SetPrototype(aCx, object_handle(&obj), object_handle(&proto)); - raw.reflector().set_jsobject(obj); +raw.reflector().set_jsobject(obj); - RegisterBindings::Register(aCx, obj); -}); +RegisterBindings::Register(aCx, obj); Temporary::new(raw)""" % CreateBindingJSObject(self.descriptor)) @@ -1899,9 +1984,9 @@ class CGAbstractExternMethod(CGAbstractMethod): Abstract base class for codegen of implementation-only (no declaration) static methods. """ - def __init__(self, descriptor, name, returnType, args): + def __init__(self, descriptor, name, returnType, args, pub=False): CGAbstractMethod.__init__(self, descriptor, name, returnType, args, - inline=False, extern=True) + inline=False, extern=True, pub=pub) class PropertyArrays(): def __init__(self, descriptor): @@ -1962,14 +2047,14 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod): """ def __init__(self, descriptor, properties): assert not descriptor.interface.isCallback() - args = [Argument('*mut JSContext', 'aCx'), Argument('*mut JSObject', 'aGlobal'), + args = [Argument('*mut JSContext', 'aCx'), Argument('*mut JSObject', 'aGlobal', mutable=True), Argument('*mut JSObject', 'aReceiver')] CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', '*mut JSObject', args) self.properties = properties def definition_body(self): protoChain = self.descriptor.prototypeChain if len(protoChain) == 1: - getParentProto = "JS_GetObjectPrototype(aCx, aGlobal)" + getParentProto = "JS_GetObjectPrototype(aCx, object_handle(&aGlobal))" else: parentProtoName = self.descriptor.prototypeChain[-2] getParentProto = ("%s::GetProtoObject(aCx, aGlobal, aReceiver)" % @@ -1979,10 +2064,7 @@ def definition_body(self): "assert!(parentProto.is_not_null());\n") % getParentProto if self.descriptor.concrete: - if self.descriptor.proxy: - domClass = "&Class" - else: - domClass = "&Class.dom_class" + domClass = "&Class.dom_class" else: domClass = "ptr::null()" @@ -2000,12 +2082,13 @@ def definition_body(self): else: constructor = 'None' - call = """return CreateInterfaceObjects2(aCx, aGlobal, aReceiver, parentProto, + call = """return CreateInterfaceObjects2(aCx, object_handle(&aGlobal), aReceiver, object_handle(&parentProto), &PrototypeClass, %s, %s, &sNativeProperties);""" % (constructor, domClass) return CGList([ + CGGeneric("let _ac = JSAutoCompartment::new(aCx, aGlobal);"), CGGeneric(getParentProto), CGGeneric(call % self.properties.variableNames()) ], "\n") @@ -2089,6 +2172,7 @@ def define(self): def definition_body(self): body = """\ let traps = ProxyTraps { + preventExtensions: None, getPropertyDescriptor: Some(getPropertyDescriptor), getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor), defineProperty: Some(defineProperty), @@ -2103,19 +2187,16 @@ def definition_body(self): keys: ptr::null(), iterate: None, + isExtensible: None, call: None, construct: None, nativeCall: ptr::null(), hasInstance: None, - typeOf: None, objectClassIs: None, - obj_toString: Some(obj_toString), fun_toString: None, //regexp_toShared: ptr::null(), defaultValue: None, - iteratorNext: None, finalize: Some(%s), - getElementIfPresent: None, getPrototypeOf: None, trace: Some(%s) }; @@ -2278,7 +2359,7 @@ def __init__(self, returnType, argsPre, arguments, nativeMethodName, static, i in range(argConversionStartsAt, self.argCount)]) cgThings.append(CGCallGenerator( - ' false as JSBool' if self.isFallible() else None, + ' false' if self.isFallible() else None, self.getArguments(), self.argsPre, returnType, self.extendedAttributes, descriptor, nativeMethodName, static)) @@ -2392,7 +2473,7 @@ def __init__(self, argsPre, argType, nativeMethodName, descriptor, attr): setter=True) def wrap_return_value(self): # We have no return value - return "\nreturn 1;" + return "\nreturn true;" def getArgc(self): return "1" def getArgvDecl(self): @@ -2408,13 +2489,13 @@ class CGAbstractBindingMethod(CGAbstractExternMethod): CGThing which is already properly indented. """ def __init__(self, descriptor, name, args, unwrapFailureCode=None): - CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args) + CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args) if unwrapFailureCode is None: self.unwrapFailureCode = ( 'throw_type_error(cx, "\\"this\\" object does not ' 'implement interface %s.");\n' - 'return 0;' % descriptor.interface.identifier.name) + 'return false;' % descriptor.interface.identifier.name) else: self.unwrapFailureCode = unwrapFailureCode @@ -2427,9 +2508,9 @@ def definition_body(self): FakeCastableDescriptor(self.descriptor), "obj", self.unwrapFailureCode)) unwrapThis = CGGeneric( - "let obj: *mut JSObject = JS_THIS_OBJECT(cx, vp as *mut JSVal);\n" + "let obj: *mut JSObject = JS_THIS_OBJECT(cx, vp);\n" "if obj.is_null() {\n" - " return false as JSBool;\n" + " return false;\n" "}\n" "\n" "let this: JS<%s> = %s;\n" % (self.descriptor.concreteType, unwrapThis)) @@ -2453,7 +2534,7 @@ def __init__(self, descriptor, name): Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp'), ] - CGAbstractMethod.__init__(self, descriptor, name, "JSBool", args, extern=True) + CGAbstractMethod.__init__(self, descriptor, name, "bool", args, extern=True) def definition_body(self): return self.generate_code() @@ -2473,8 +2554,8 @@ def __init__(self, descriptor): def generate_code(self): return CGGeneric( - "let _info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" - "return CallJitMethodOp(_info, cx, obj, this.unsafe_get() as *mut libc::c_void, argc, vp);") + "let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" + "return CallJitMethodOp(info, cx, object_handle(&obj), this.unsafe_get() as *const libc::c_void, argc, vp);") class CGSpecializedMethod(CGAbstractExternMethod): """ @@ -2487,7 +2568,7 @@ def __init__(self, descriptor, method): args = [Argument('*mut JSContext', 'cx'), Argument('JSHandleObject', '_obj'), Argument('*const %s' % descriptor.concreteType, 'this'), Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp')] - CGAbstractExternMethod.__init__(self, descriptor, name, 'JSBool', args) + CGAbstractExternMethod.__init__(self, descriptor, name, 'bool', args) def definition_body(self): nativeName = CGSpecializedMethod.makeNativeName(self.descriptor, @@ -2495,7 +2576,8 @@ def definition_body(self): return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(), self.descriptor, self.method), pre="let this = JS::from_raw(this);\n" - "let this = this.root();\n") + "let mut this = this.root();\n" + "this.init();\n") @staticmethod def makeNativeName(descriptor, method): @@ -2537,8 +2619,8 @@ def __init__(self, descriptor, lenientThis=False): def generate_code(self): return CGGeneric( - "let info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" - "return CallJitPropertyOp(info, cx, obj, this.unsafe_get() as *mut libc::c_void, vp);\n") + "let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" + "return CallJitGetterOp(info, cx, object_handle(&obj), this.unsafe_get() as *const libc::c_void, vp);\n") class CGSpecializedGetter(CGAbstractExternMethod): """ @@ -2552,7 +2634,7 @@ def __init__(self, descriptor, attr): Argument('JSHandleObject', '_obj'), Argument('*const %s' % descriptor.concreteType, 'this'), Argument('*mut JSVal', 'vp') ] - CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args) + CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args) def definition_body(self): nativeName = CGSpecializedGetter.makeNativeName(self.descriptor, @@ -2612,12 +2694,12 @@ def generate_code(self): return CGGeneric( "let mut undef = UndefinedValue();\n" "let argv: *mut JSVal = if argc != 0 { JS_ARGV(cx, vp) } else { &mut undef as *mut JSVal };\n" - "let info: *const JSJitInfo = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" - "if CallJitPropertyOp(info, cx, obj, this.unsafe_get() as *mut libc::c_void, argv) == 0 {\n" - " return 0;\n" + "let info = RUST_FUNCTION_VALUE_TO_JITINFO(JS_CALLEE(cx, vp));\n" + "if !CallJitSetterOp(info, cx, object_handle(&obj), this.unsafe_get() as *const libc::c_void, argv) {\n" + " return false;\n" "}\n" "*vp = UndefinedValue();\n" - "return 1;") + "return true;") class CGSpecializedSetter(CGAbstractExternMethod): """ @@ -2631,7 +2713,7 @@ def __init__(self, descriptor, attr): Argument('JSHandleObject', '_obj'), Argument('*const %s' % descriptor.concreteType, 'this'), Argument('*mut JSVal', 'argv')] - CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args) + CGAbstractExternMethod.__init__(self, descriptor, name, "bool", args) def definition_body(self): nativeName = CGSpecializedSetter.makeNativeName(self.descriptor, @@ -2662,7 +2744,7 @@ def generate_code(self): "let argv = JS_ARGV(cx, vp);\n" "if (argc == 0) {\n" " throw_type_error(cx, \"Not enough arguments to %s setter.\");\n" - " return 0;\n" + " return false;\n" "}\n" % self.attr.identifier.name) call = CGSetterCall([], self.attr.type, nativeName, self.descriptor, self.attr) @@ -2678,30 +2760,34 @@ def __init__(self, descriptor, member): self.member = member self.descriptor = descriptor - def defineJitInfo(self, infoName, opName, infallible): - protoID = "PrototypeList::id::%s as u32" % self.descriptor.name + def defineJitInfo(self, infoName, opName, opType, infallible, returnTypes): + protoID = "PrototypeList::id::%s as u16" % self.descriptor.name depth = self.descriptor.interface.inheritanceDepth() - failstr = "true" if infallible else "false" + failstr = "1" if infallible else "0" + retType = reduce(CGMemberJITInfo.getSingleReturnType, returnTypes, "") return ("\n" "static %s: JSJitInfo = JSJitInfo {\n" " op: %s as *const u8,\n" " protoID: %s,\n" " depth: %s,\n" - " isInfallible: %s, /* False in setters. */\n" - " isConstant: false /* Only relevant for getters. */\n" - "};\n" % (infoName, opName, protoID, depth, failstr)) + " type_and_aliasSet: %s as u8 | (2 /*AliasEverything*/ << 4),\n" + " returnType: %s as u8,\n" + " infallible_and_isMovable_and_isInSlot_and_isTypedMethod_and_slotIndex: 0,\n" + "};\n" % (infoName, opName, protoID, depth, opType, retType)) def define(self): if self.member.isAttr(): getterinfo = ("%s_getterinfo" % self.member.identifier.name) getter = ("get_%s" % self.member.identifier.name) getterinfal = "infallible" in self.descriptor.getExtendedAttributes(self.member, getter=True) - result = self.defineJitInfo(getterinfo, getter, getterinfal) + result = self.defineJitInfo(getterinfo, getter, "Getter", getterinfal, + [self.member.type]) if not self.member.readonly: setterinfo = ("%s_setterinfo" % self.member.identifier.name) setter = ("set_%s" % self.member.identifier.name) # Setters are always fallible, since they have to do a typed unwrap. - result += self.defineJitInfo(setterinfo, setter, False) + result += self.defineJitInfo(setterinfo, setter, "Setter", False, + [BuiltinTypes[IDLBuiltinType.Types.void]]) return result if self.member.isMethod(): methodinfo = ("%s_methodinfo" % self.member.identifier.name) @@ -2721,10 +2807,90 @@ def define(self): # No arguments and infallible return boxing methodInfal = True - result = self.defineJitInfo(methodinfo, method, methodInfal) + result = self.defineJitInfo(methodinfo, method, "Method", methodInfal, + [s[0] for s in sigs]) return result raise TypeError("Illegal member type to CGPropertyJITInfo") + @staticmethod + def getJSReturnTypeTag(t): + if t.nullable(): + # Sometimes it might return null, sometimes not + return "JSVAL_TYPE_UNKNOWN" + if t.isVoid(): + # No return, every time + return "JSVAL_TYPE_UNDEFINED" + if t.isArray(): + # No idea yet + assert False + if t.isSequence(): + return "JSVAL_TYPE_OBJECT" + if t.isGeckoInterface(): + return "JSVAL_TYPE_OBJECT" + if t.isString(): + return "JSVAL_TYPE_STRING" + if t.isEnum(): + return "JSVAL_TYPE_STRING" + if t.isCallback(): + return "JSVAL_TYPE_OBJECT" + if t.isAny(): + # The whole point is to return various stuff + return "JSVAL_TYPE_UNKNOWN" + if t.isObject(): + return "JSVAL_TYPE_OBJECT" + if t.isSpiderMonkeyInterface(): + return "JSVAL_TYPE_OBJECT" + if t.isUnion(): + u = t.unroll() + if u.hasNullableType: + # Might be null or not + return "JSVAL_TYPE_UNKNOWN" + return reduce(CGMemberJITInfo.getSingleReturnType, + u.flatMemberTypes, "") + if t.isDictionary(): + return "JSVAL_TYPE_OBJECT" + if t.isDate(): + return "JSVAL_TYPE_OBJECT" + if not t.isPrimitive(): + raise TypeError("No idea what type " + str(t) + " is.") + tag = t.tag() + if tag == IDLType.Tags.bool: + return "JSVAL_TYPE_BOOLEAN" + if tag in [IDLType.Tags.int8, IDLType.Tags.uint8, + IDLType.Tags.int16, IDLType.Tags.uint16, + IDLType.Tags.int32]: + return "JSVAL_TYPE_INT32" + if tag in [IDLType.Tags.int64, IDLType.Tags.uint64, + IDLType.Tags.float, + IDLType.Tags.double]: + # These all use JS_NumberValue, which can return int or double. + # But TI treats "double" as meaning "int or double", so we're + # good to return JSVAL_TYPE_DOUBLE here. + return "JSVAL_TYPE_DOUBLE" + if tag != IDLType.Tags.uint32: + raise TypeError("No idea what type " + str(t) + " is.") + # uint32 is sometimes int and sometimes double. + return "JSVAL_TYPE_DOUBLE" + + @staticmethod + def getSingleReturnType(existingType, t): + type = CGMemberJITInfo.getJSReturnTypeTag(t) + if existingType == "": + # First element of the list; just return its type + return type + + if type == existingType: + return existingType + if ((type == "JSVAL_TYPE_DOUBLE" and + existingType == "JSVAL_TYPE_INT32") or + (existingType == "JSVAL_TYPE_DOUBLE" and + type == "JSVAL_TYPE_INT32")): + # Promote INT32 to DOUBLE as needed + return "JSVAL_TYPE_DOUBLE" + # Different types + return "JSVAL_TYPE_UNKNOWN" + + def getEnumValueName(value): # Some enum values can be empty strings. Others might have weird # characters in them. Deal with the former by returning "_empty", @@ -3508,7 +3674,7 @@ def __init__(self, descriptor, operation): template, _, declType, needsRooting = getJSToNativeConversionTemplate( argument.type, descriptor, treatNullAs=argument.treatNullAs) templateValues = { - "val": "(*desc).value", + "val": "desc.value", } self.cgRoot.prepend(instantiateJSToNativeConversionTemplate( template, templateValues, declType, argument.identifier.name, @@ -3571,7 +3737,7 @@ def __init__(self, descriptor): class CGProxyUnwrap(CGAbstractMethod): def __init__(self, descriptor): - args = [Argument('*mut JSObject', 'obj')] + args = [Argument('JSHandleObject', 'obj')] CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", '*const ' + descriptor.concreteType, args, alwaysInline=True) def definition_body(self): @@ -3579,14 +3745,15 @@ def definition_body(self): obj = js::UnwrapObject(obj); }*/ //MOZ_ASSERT(IsProxy(obj)); -let box_ = GetProxyPrivate(obj).to_private() as *const %s; +let box_ = GetProxyPrivate(*obj).to_private() as *const %s; return box_;""" % self.descriptor.concreteType) class CGDOMJSProxyHandler_getOwnPropertyDescriptor(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'), - Argument('jsid', 'id'), Argument('bool', 'set'), - Argument('*mut JSPropertyDescriptor', 'desc')] + args = [Argument('*mut JSContext', 'cx'), Argument('JSHandleObject', 'proxy'), + Argument('JSHandleId', 'id'), + Argument('MutableHandle', 'desc', mutable=True), + Argument('u32', 'flags')] CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor", "bool", args) self.descriptor = descriptor @@ -3596,12 +3763,12 @@ def getBody(self): setOrIndexedGet = "" if indexedGetter or indexedSetter: - setOrIndexedGet += "let index = GetArrayIndexFromId(cx, id);\n" + setOrIndexedGet += "let index = GetArrayIndexFromId(cx, *id);\n" if indexedGetter: readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None) - fillDescriptor = "FillPropertyDescriptor(&mut *desc, proxy, %s);\nreturn true;" % readonly - templateValues = {'jsvalRef': '(*desc).value', 'successCode': fillDescriptor} + fillDescriptor = "FillPropertyDescriptor(&mut *desc, *proxy, %s);\nreturn true;" % readonly + templateValues = {'jsvalRef': 'desc.value', 'successCode': fillDescriptor} get = ("if index.is_some() {\n" + " let index = index.unwrap();\n" + " let this = UnwrapProxy(proxy);\n" + @@ -3611,22 +3778,22 @@ def getBody(self): "}\n") if indexedSetter or self.descriptor.operations['NamedSetter']: - setOrIndexedGet += "if set != 0 {\n" + setOrIndexedGet += "if flags & 0x02 /*SET*/ == 0 {\n" if indexedSetter: setOrIndexedGet += (" if index.is_some() {\n" + " let index = index.unwrap();\n") if not 'IndexedCreator' in self.descriptor.operations: # FIXME need to check that this is a 'supported property index' assert False - setOrIndexedGet += (" FillPropertyDescriptor(&mut *desc, proxy, false);\n" + + setOrIndexedGet += (" FillPropertyDescriptor(&mut *desc, *proxy, false);\n" + " return true;\n" + " }\n") if self.descriptor.operations['NamedSetter']: - setOrIndexedGet += " if RUST_JSID_IS_STRING(id) {\n" + setOrIndexedGet += " if RUST_JSID_IS_STRING(*id) {\n" if not 'NamedCreator' in self.descriptor.operations: # FIXME need to check that this is a 'supported property name' assert False - setOrIndexedGet += (" FillPropertyDescriptor(&mut *desc, proxy, false);\n" + + setOrIndexedGet += (" FillPropertyDescriptor(&mut *desc, *proxy, false);\n" + " return true;\n" + " }\n") setOrIndexedGet += "}" @@ -3636,21 +3803,21 @@ def getBody(self): "}") setOrIndexedGet += "\n\n" elif indexedGetter: - setOrIndexedGet += ("if !set {\n" + + setOrIndexedGet += ("if flags & 0x02 == 0 /*SET*/ {\n" + CGIndenter(CGGeneric(get)).define() + "}\n\n") namedGetter = self.descriptor.operations['NamedGetter'] if namedGetter: readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None) - fillDescriptor = "FillPropertyDescriptor(&mut *desc, proxy, %s);\nreturn true;" % readonly - templateValues = {'jsvalRef': '(*desc).value', 'successCode': fillDescriptor} + fillDescriptor = "FillPropertyDescriptor(&mut *desc, *proxy, %s);\nreturn true;" % readonly + templateValues = {'jsvalRef': 'desc.value', 'successCode': fillDescriptor} # Once we start supporting OverrideBuiltins we need to make # ResolveOwnProperty or EnumerateOwnProperties filter out named # properties that shadow prototype properties. namedGet = ("\n" + - "if !set && RUST_JSID_IS_STRING(id) != 0 && !HasPropertyOnPrototype(cx, proxy, id) {\n" + - " let name = jsid_to_str(cx, id);\n" + + "if flags & 0x02 /*SET*/ == 0 && RUST_JSID_IS_STRING(*id) && !HasPropertyOnPrototype(cx, proxy, id) {\n" + + " let name = jsid_to_str(cx, *id);\n" + " let this = UnwrapProxy(proxy);\n" + " let this = JS::from_raw(this);\n" + " let this = this.root();\n" + @@ -3659,21 +3826,21 @@ def getBody(self): else: namedGet = "" - return setOrIndexedGet + """let expando: *mut JSObject = GetExpandoObject(proxy); + return setOrIndexedGet + """let expando: *mut JSObject = GetExpandoObject(*proxy); //if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) { if expando.is_not_null() { - let flags = if set { JSRESOLVE_ASSIGNING } else { 0 } | JSRESOLVE_QUALIFIED; - if JS_GetPropertyDescriptorById(cx, expando, id, flags, desc) == 0 { + let flags = if flags & 0x02 /*SET*/ != 0 { JSRESOLVE_ASSIGNING } else { 0 } | JSRESOLVE_QUALIFIED; + if !JS_GetPropertyDescriptorById(cx, object_handle(&expando), id, flags, mut_handle(desc.unnamed_field1)) { return false; } - if (*desc).obj.is_not_null() { + if desc.obj.is_not_null() { // Pretend the property lives on the wrapper. - (*desc).obj = proxy; + desc.obj = *proxy; return true; } } """ + namedGet + """ -(*desc).obj = ptr::null_mut(); +desc.obj = ptr::null_mut(); return true;""" def definition_body(self): @@ -3681,9 +3848,9 @@ def definition_body(self): class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'), - Argument('jsid', 'id'), - Argument('*const JSPropertyDescriptor', 'desc')] + args = [Argument('*mut JSContext', 'cx'), Argument('JSHandleObject', 'proxy'), + Argument('JSHandleId', 'id'), + Argument('MutableHandle', 'desc', mutable=True)] CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "bool", args) self.descriptor = descriptor def getBody(self): @@ -3693,7 +3860,7 @@ def getBody(self): if indexedSetter: if not (self.descriptor.operations['IndexedCreator'] is indexedSetter): raise TypeError("Can't handle creator that's different from the setter") - set += ("let index = GetArrayIndexFromId(cx, id);\n" + + set += ("let index = GetArrayIndexFromId(cx, *id);\n" + "if index.is_some() {\n" + " let index = index.unwrap();\n" + " let this = UnwrapProxy(proxy);\n" + @@ -3703,7 +3870,7 @@ def getBody(self): " return true;\n" + "}\n") elif self.descriptor.operations['IndexedGetter']: - set += ("if GetArrayIndexFromId(cx, id).is_some() {\n" + + set += ("if GetArrayIndexFromId(cx, *id).is_some() {\n" + " return false;\n" + " //return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" + "}\n") % self.descriptor.name @@ -3712,7 +3879,7 @@ def getBody(self): if namedSetter: if not self.descriptor.operations['NamedCreator'] is namedSetter: raise TypeError("Can't handle creator that's different from the setter") - set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" + + set += ("if RUST_JSID_IS_STRING(*id) {\n" + " let name = jsid_to_str(cx, id);\n" + " let this = UnwrapProxy(proxy);\n" + " let this = JS::from_raw(this);\n" + @@ -3720,8 +3887,8 @@ def getBody(self): CGIndenter(CGProxyNamedSetter(self.descriptor)).define() + "\n" + "}\n") elif self.descriptor.operations['NamedGetter']: - set += ("if RUST_JSID_IS_STRING(id) {\n" + - " let name = jsid_to_str(cx, id);\n" + + set += ("if RUST_JSID_IS_STRING(*id) {\n" + + " let name = jsid_to_str(cx, *id);\n" + " let this = UnwrapProxy(proxy);\n" + " let this = JS::from_raw(this);\n" + " let this = this.root();\n" + @@ -3739,14 +3906,14 @@ def definition_body(self): class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'), - Argument('jsid', 'id'), Argument('*mut bool', 'bp')] + args = [Argument('*mut JSContext', 'cx'), Argument('JSHandleObject', 'proxy'), + Argument('JSHandleId', 'id'), Argument('*mut bool', 'bp')] CGAbstractExternMethod.__init__(self, descriptor, "hasOwn", "bool", args) self.descriptor = descriptor def getBody(self): indexedGetter = self.descriptor.operations['IndexedGetter'] if indexedGetter: - indexed = ("let index = GetArrayIndexFromId(cx, id);\n" + + indexed = ("let index = GetArrayIndexFromId(cx, *id);\n" + "if index.is_some() {\n" + " let index = index.unwrap();\n" + " let this = UnwrapProxy(proxy);\n" + @@ -3761,8 +3928,8 @@ def getBody(self): namedGetter = self.descriptor.operations['NamedGetter'] if namedGetter: - named = ("if RUST_JSID_IS_STRING(id) != 0 && !HasPropertyOnPrototype(cx, proxy, id) {\n" + - " let name = jsid_to_str(cx, id);\n" + + named = ("if RUST_JSID_IS_STRING(*id) && !HasPropertyOnPrototype(cx, proxy, id) {\n" + + " let name = jsid_to_str(cx, *id);\n" + " let this = UnwrapProxy(proxy);\n" + " let this = JS::from_raw(this);\n" + " let this = this.root();\n" + @@ -3774,11 +3941,9 @@ def getBody(self): else: named = "" - return indexed + """let expando: *mut JSObject = GetExpandoObject(proxy); + return indexed + """let expando = GetExpandoObject(*proxy); if expando.is_not_null() { - let mut b: JSBool = 1; - let ok = JS_HasPropertyById(cx, expando, id, &mut b) != 0; - *bp = b != 0; + let ok = JS_HasPropertyById(cx, object_handle(&expando), id, bp); if !ok || *bp { return ok; } @@ -3792,32 +3957,32 @@ def definition_body(self): class CGDOMJSProxyHandler_get(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'), - Argument('*mut JSObject', 'receiver'), Argument('jsid', 'id'), - Argument('*mut JSVal', 'vp')] + args = [Argument('*mut JSContext', 'cx'), Argument('JSHandleObject', 'proxy'), + Argument('JSHandleObject', 'receiver'), Argument('JSHandleId', 'id'), + Argument('JSMutableHandleValue', 'vp')] CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args) self.descriptor = descriptor def getBody(self): - getFromExpando = """let expando = GetExpandoObject(proxy); + getFromExpando = """let expando = GetExpandoObject(*proxy); if expando.is_not_null() { - let mut hasProp = 0; - if JS_HasPropertyById(cx, expando, id, &mut hasProp) == 0 { + let mut hasProp = false; + if !JS_HasPropertyById(cx, object_handle(&expando), id, &mut hasProp) { return false; } - if hasProp != 0 { - return JS_GetPropertyById(cx, expando, id, vp) != 0; + if hasProp { + return JS_GetPropertyById(cx, object_handle(&expando), id, vp); } }""" templateValues = { - 'jsvalRef': '*vp', + 'jsvalRef': '*vp.unnamed_field1', 'successCode': 'return true;', } indexedGetter = self.descriptor.operations['IndexedGetter'] if indexedGetter: - getIndexedOrExpando = ("let index = GetArrayIndexFromId(cx, id);\n" + + getIndexedOrExpando = ("let index = GetArrayIndexFromId(cx, *id);\n" + "if index.is_some() {\n" + " let index = index.unwrap();\n" + " let this = UnwrapProxy(proxy);\n" + @@ -3836,8 +4001,8 @@ def getBody(self): namedGetter = self.descriptor.operations['NamedGetter'] if namedGetter and False: #XXXjdm unfinished - getNamed = ("if (JSID_IS_STRING(id)) {\n" + - " let name = jsid_to_str(cx, id);\n" + + getNamed = ("if (JSID_IS_STRING(*id)) {\n" + + " let name = jsid_to_str(cx, *id);\n" + " let this = UnwrapProxy(proxy);\n" + " let this = JS::from_raw(this);\n" + " let this = this.root();\n" + @@ -3851,7 +4016,7 @@ def getBody(self): %s let mut found = false; -if !GetPropertyOnPrototype(cx, proxy, id, &mut found, vp) { +if !GetPropertyOnPrototype(cx, proxy, id, &mut found, Some(mut_value_handle(vp.unnamed_field1))) { return false; } @@ -3859,7 +4024,7 @@ def getBody(self): return true; } %s -*vp = UndefinedValue(); +*vp.unnamed_field1 = UndefinedValue(); return true;""" % (getIndexedOrExpando, getNamed) def definition_body(self): @@ -3867,7 +4032,7 @@ def definition_body(self): class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod): def __init__(self, descriptor): - args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy')] + args = [Argument('*mut JSContext', 'cx'), Argument('JSHandleObject', 'proxy')] CGAbstractExternMethod.__init__(self, descriptor, "obj_toString", "*mut JSString", args) self.descriptor = descriptor def getBody(self): @@ -3901,9 +4066,9 @@ class CGAbstractClassHook(CGAbstractExternMethod): Meant for implementing JSClass hooks, like Finalize or Trace. Does very raw 'this' unwrapping as it assumes that the unwrapped type is always known. """ - def __init__(self, descriptor, name, returnType, args): + def __init__(self, descriptor, name, returnType, args, pub=False): CGAbstractExternMethod.__init__(self, descriptor, name, returnType, - args) + args, pub=pub) def definition_body_prologue(self): return CGGeneric("""\ @@ -3934,7 +4099,7 @@ class CGClassTraceHook(CGAbstractClassHook): def __init__(self, descriptor): args = [Argument('*mut JSTracer', 'trc'), Argument('*mut JSObject', 'obj')] CGAbstractClassHook.__init__(self, descriptor, TRACE_HOOK_NAME, 'void', - args) + args, pub=True) def generate_code(self): return CGGeneric("(*this).trace(%s);" % self.args[0].name) @@ -3946,7 +4111,7 @@ class CGClassConstructHook(CGAbstractExternMethod): def __init__(self, descriptor): args = [Argument('*mut JSContext', 'cx'), Argument('u32', 'argc'), Argument('*mut JSVal', 'vp')] CGAbstractExternMethod.__init__(self, descriptor, CONSTRUCT_HOOK_NAME, - 'JSBool', args) + 'bool', args) self._ctor = self.descriptor.interface.ctor() def define(self): @@ -3976,16 +4141,6 @@ def __init__(self, descriptor): def generate_code(self): return CGGeneric(finalizeHook(self.descriptor, self.name, self.args[0].name)) -class CGDOMJSProxyHandlerDOMClass(CGThing): - def __init__(self, descriptor): - CGThing.__init__(self) - self.descriptor = descriptor - - def define(self): - return """ -static Class: DOMClass = """ + DOMClass(self.descriptor) + """; - -""" class CGInterfaceTrait(CGThing): @@ -4171,8 +4326,8 @@ def __init__(self, descriptor): if descriptor.concrete: if descriptor.proxy: #cgThings.append(CGProxyIsProxy(descriptor)) + cgThings.append(CGDOMProxyJSClass(descriptor)) cgThings.append(CGProxyUnwrap(descriptor)) - cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor)) cgThings.append(CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor)) cgThings.append(CGDOMJSProxyHandler_obj_toString(descriptor)) cgThings.append(CGDOMJSProxyHandler_get(descriptor)) @@ -4368,7 +4523,7 @@ def indent(s): conversion = "Some(%s)" % conversion conversion = ( - "match get_dictionary_property(cx, object, \"%s\") {\n" + "match get_dictionary_property(cx, object_handle(&object), \"%s\") {\n" " Err(()) => return Err(()),\n" " Ok(Some(value)) => {\n" "%s\n" @@ -4494,28 +4649,42 @@ def __init__(self, config, prefix, webIDLFile): 'js::{JS_ARGV, JS_CALLEE, JS_THIS_OBJECT}', 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS}', 'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}', - 'js::{JSCLASS_RESERVED_SLOTS_MASK, JSID_VOID, JSJitInfo}', + 'js::{JSCLASS_RESERVED_SLOTS_MASK, JSJitInfo}', 'js::{JSPROP_ENUMERATE, JSPROP_NATIVE_ACCESSORS, JSPROP_SHARED}', 'js::{JSRESOLVE_ASSIGNING, JSRESOLVE_QUALIFIED}', 'js::jsapi::{JS_CallFunctionValue, JS_GetClass, JS_GetGlobalForObject}', 'js::jsapi::{JS_GetObjectPrototype, JS_GetProperty, JS_GetPropertyById}', - 'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot}', + 'js::jsapi::{JS_GetPropertyDescriptorById, JS_GetReservedSlot, Struct_JSClass}', 'js::jsapi::{JS_HasProperty, JS_HasPropertyById, JS_IsExceptionPending}', - 'js::jsapi::{JS_NewObject, JS_ObjectIsCallable, JS_SetPrototype}', - 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSBool, JSContext}', + 'js::jsapi::{JS_NewObject, JS_ObjectIsCallable, JS_SetPrototype, JSHandleId}', + 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSContext, JSID_VOID}', 'js::jsapi::{JSClass, JSFreeOp, JSFunctionSpec, JSHandleObject, jsid}', - 'js::jsapi::{JSNativeWrapper, JSObject, JSPropertyDescriptor, JS_ArrayIterator}', + 'js::jsapi::{JSNativeWrapper, JSObject, JSPropertyDescriptor}', 'js::jsapi::{JSPropertyOpWrapper, JSPropertySpec, JS_PropertyStub}', + 'js::jsapi::{Struct_JSPropertySpec, Struct_JSFunctionSpec, Struct_JSNativeWrapper}', + 'js::jsapi::{Struct_JSStrictPropertyOpWrapper, Struct_JSPropertyOpWrapper}', 'js::jsapi::{JSStrictPropertyOpWrapper, JSString, JSTracer, JS_ConvertStub}', 'js::jsapi::{JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub}', - 'js::jsval::JSVal', + 'js::jsapi::{JSMutableHandleValue, JS_DeletePropertyStub, MutableHandle}', + 'js::jsapi::JS_GlobalObjectTraceHook', + 'js::jsfriendapi::{Getter, Setter, Method}', + 'js::jsval::{JSVal, JSVAL_TYPE_DOUBLE, JSVAL_TYPE_INT32, JSVAL_TYPE_UNDEFINED}', + 'js::jsval::{JSVAL_TYPE_BOOLEAN, JSVAL_TYPE_MAGIC, JSVAL_TYPE_STRING}', + 'js::jsval::{JSVAL_TYPE_NULL, JSVAL_TYPE_OBJECT, JSVAL_TYPE_UNKNOWN}', 'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}', 'js::jsval::{NullValue, UndefinedValue}', - 'js::glue::{CallJitMethodOp, CallJitPropertyOp, CreateProxyHandler}', + 'js::glue::{CallJitMethodOp, CallJitGetterOp, CreateProxyHandler}', 'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps}', - 'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO}', - 'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING}', - 'js::rust::with_compartment', + 'js::glue::{RUST_FUNCTION_VALUE_TO_JITINFO, CallJitSetterOp}', + 'js::glue::{RUST_JS_NumberValue, RUST_JSID_IS_STRING, CallFunctionValue}', + 'js::glue::{proxy_LookupGeneric, proxy_LookupProperty, proxy_LookupElement}', + 'js::glue::{proxy_DefineGeneric, proxy_DefineProperty, proxy_DefineElement}', + 'js::glue::{proxy_GetGeneric, proxy_SetGeneric, proxy_SetProperty, proxy_SetElement}', + 'js::glue::{proxy_GetGenericAttributes, proxy_SetGenericAttributes, proxy_DeleteProperty}', + 'js::glue::{proxy_DeleteElement, proxy_Trace, proxy_WeakmapKeyDelegate, proxy_Finalize}', + 'js::glue::{proxy_HasInstance, proxy_innerObject, proxy_Watch}', + 'js::glue::{proxy_Unwatch, proxy_Slice, proxy_Convert, proxy_GetProperty, proxy_GetElement}', + 'js::rust::{JSAutoRequest, JSAutoCompartment}', 'dom::types::*', 'dom::bindings', 'dom::bindings::global::GlobalRef', @@ -4523,9 +4692,9 @@ def __init__(self, config, prefix, webIDLFile): 'dom::bindings::js::{JS, JSRef, Root, RootedReference, Temporary}', 'dom::bindings::js::{OptionalRootable, OptionalRootedRootable, ResultRootable}', '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::{CreateDOMGlobal, CreateInterfaceObjects2, value_handle}', + 'dom::bindings::utils::{ConstantSpec, mut_value_handle, mut_handle, object_handle}', + 'dom::bindings::utils::{dom_object_slot, DOM_OBJECT_SLOT, DOMClass, id_handle}', 'dom::bindings::utils::{DOMJSClass, JSCLASS_DOM_GLOBAL}', 'dom::bindings::utils::{FindEnumStringIndex, GetArrayIndexFromId}', 'dom::bindings::utils::{GetPropertyOnPrototype, GetProtoOrIfaceArray}', @@ -4944,7 +5113,10 @@ def getMethodImpls(self, method): bodyWithThis = string.Template( setupCall+ - "let thisObjJS = WrapCallThisObject(s.GetContext(), thisObj);\n" + "let cx = s.GetContext();\n" + "let _ar = JSAutoRequest::new(cx);\n" + "let _ar = JSAutoCompartment::new(cx, self.parent.callback());\n" + "let thisObjJS = WrapCallThisObject(cx, thisObj);\n" "if thisObjJS.is_null() {\n" " return Err(FailureUnknown);\n" "}\n" @@ -5103,14 +5275,14 @@ def getImpl(self): "${returnResult}").substitute(replacements) return CGList([ CGGeneric(pre), - CGWrapper(CGIndenter(CGGeneric(body)), - pre="with_compartment(cx, self.parent.callback(), || {\n", - post="})") + CGWrapper(CGGeneric(body), + pre="let _ar = JSAutoRequest::new(cx);\n" + "let _ac = JSAutoCompartment::new(cx, self.parent.callback());\n") ], "\n").define() def getResultConversion(self): replacements = { - "val": "rval", + "val": "*rval", "declName": "rvalDecl", } @@ -5242,7 +5414,8 @@ def __init__(self, sig, name, descriptorProvider, needThisHandling, rethrowConte CallbackMember.__init__(self, sig, name, descriptorProvider, needThisHandling, rethrowContentException) def getRvalDecl(self): - return "let mut rval = UndefinedValue();\n" + return """let mut rval = UndefinedValue();\n +let rval = mut_value_handle(&mut rval);\n""" def getCall(self): replacements = { @@ -5250,17 +5423,17 @@ def getCall(self): "getCallable": self.getCallableDecl() } if self.argCount > 0: - replacements["argv"] = "argv.as_mut_ptr()" + replacements["argv"] = "argv.as_ptr()" replacements["argc"] = "argc" else: replacements["argv"] = "nullptr" replacements["argc"] = "0" return string.Template("${getCallable}" "let ok = unsafe {\n" - " JS_CallFunctionValue(cx, ${thisObj}, callable,\n" - " ${argc}, ${argv}, &mut rval)\n" + " CallFunctionValue(cx, object_handle(&${thisObj}), value_handle(&callable),\n" + " ${argc} as libc::size_t, ${argv}, mut_value_handle(rval.unnamed_field1))\n" "};\n" - "if ok == 0 {\n" + "if !ok {\n" " return Err(FailureUnknown);\n" "}\n").substitute(replacements) @@ -5304,7 +5477,7 @@ def getCallableDecl(self): if not self.singleOperation: return 'JS::Rooted callable(cx);\n' + getCallableFromProp return ( - 'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback()) != 0 };\n' + 'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback()) };\n' 'let callable =\n' + CGIndenter( CGIfElseWrapper('isCallable', diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs index 2afd91fd08b8..08a3d0b9399e 100644 --- a/components/script/dom/bindings/conversions.rs +++ b/components/script/dom/bindings/conversions.rs @@ -6,22 +6,20 @@ use dom::bindings::js::{JS, JSRef, Root}; use dom::bindings::str::ByteString; -use dom::bindings::utils::{Reflectable, Reflector}; +use dom::bindings::utils::{Reflectable, Reflector, value_handle, mut_value_handle}; use dom::bindings::utils::jsstring_to_str; use dom::bindings::utils::unwrap_jsmanaged; use servo_util::str::DOMString; -use js::jsapi::{JSBool, JSContext, JSObject}; -use js::jsapi::{JS_ValueToUint64, JS_ValueToInt64}; -use js::jsapi::{JS_ValueToECMAUint32, JS_ValueToECMAInt32}; -use js::jsapi::{JS_ValueToUint16, JS_ValueToNumber, JS_ValueToBoolean}; -use js::jsapi::{JS_ValueToString, JS_GetStringCharsAndLength}; +use js::jsapi::{JSContext, JSObject, JSHandleValue}; +use js::jsapi::{JS_GetStringCharsAndLength}; use js::jsapi::{JS_NewUCStringCopyN, JS_NewStringCopyN}; use js::jsapi::{JS_WrapValue}; use js::jsval::JSVal; use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value}; use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue}; -use js::glue::RUST_JS_NumberValue; +use js::glue::{RUST_JS_NumberValue, ToString, ToBoolean, ToNumber, ToUint16, ToInt32}; +use js::glue::{ToUint32, ToInt64, ToUint64}; use libc; use std::default; use std::slice; @@ -60,7 +58,7 @@ impl ToJSValConvertible for () { impl ToJSValConvertible for JSVal { fn to_jsval(&self, cx: *mut JSContext) -> JSVal { let mut value = *self; - if unsafe { JS_WrapValue(cx, &mut value) } == 0 { + if unsafe { !JS_WrapValue(cx, mut_value_handle(&mut value)) } { fail!("JS_WrapValue failed."); } value @@ -69,9 +67,10 @@ impl ToJSValConvertible for JSVal { unsafe fn convert_from_jsval( cx: *mut JSContext, value: JSVal, - convert_fn: unsafe extern "C" fn(*mut JSContext, JSVal, *mut T) -> JSBool) -> Result { + convert_fn: unsafe extern "C" fn(*mut JSContext, JSHandleValue, *mut T) -> bool) -> Result { let mut ret = default::Default::default(); - if convert_fn(cx, value, &mut ret) == 0 { + let value = value_handle(&value); + if !convert_fn(cx, value, &mut ret) { Err(()) } else { Ok(ret) @@ -86,9 +85,9 @@ impl ToJSValConvertible for bool { } impl FromJSValConvertible<()> for bool { - fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToBoolean) }; - result.map(|b| b != 0) + fn from_jsval(_cx: *mut JSContext, val: JSVal, _option: ()) -> Result { + let val = value_handle(&val); + Ok(unsafe { ToBoolean(val) }) } } @@ -100,7 +99,7 @@ impl ToJSValConvertible for i8 { impl FromJSValConvertible<()> for i8 { fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }; + let result = unsafe { convert_from_jsval(cx, val, ToInt32) }; result.map(|v| v as i8) } } @@ -113,7 +112,7 @@ impl ToJSValConvertible for u8 { impl FromJSValConvertible<()> for u8 { fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }; + let result = unsafe { convert_from_jsval(cx, val, ToInt32) }; result.map(|v| v as u8) } } @@ -126,7 +125,7 @@ impl ToJSValConvertible for i16 { impl FromJSValConvertible<()> for i16 { fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }; + let result = unsafe { convert_from_jsval(cx, val, ToInt32) }; result.map(|v| v as i16) } } @@ -139,7 +138,7 @@ impl ToJSValConvertible for u16 { impl FromJSValConvertible<()> for u16 { fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToUint16) } + unsafe { convert_from_jsval(cx, val, ToUint16) } } } @@ -151,7 +150,7 @@ impl ToJSValConvertible for i32 { impl FromJSValConvertible<()> for i32 { fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) } + unsafe { convert_from_jsval(cx, val, ToInt32) } } } @@ -163,7 +162,7 @@ impl ToJSValConvertible for u32 { impl FromJSValConvertible<()> for u32 { fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToECMAUint32) } + unsafe { convert_from_jsval(cx, val, ToUint32) } } } @@ -177,7 +176,7 @@ impl ToJSValConvertible for i64 { impl FromJSValConvertible<()> for i64 { fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToInt64) } + unsafe { convert_from_jsval(cx, val, ToInt64) } } } @@ -191,7 +190,7 @@ impl ToJSValConvertible for u64 { impl FromJSValConvertible<()> for u64 { fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToUint64) } + unsafe { convert_from_jsval(cx, val, ToUint64) } } } @@ -205,7 +204,7 @@ impl ToJSValConvertible for f32 { impl FromJSValConvertible<()> for f32 { fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - let result = unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) }; + let result = unsafe { convert_from_jsval(cx, val, ToNumber) }; result.map(|f| f as f32) } } @@ -220,7 +219,7 @@ impl ToJSValConvertible for f64 { impl FromJSValConvertible<()> for f64 { fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result { - unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) } + unsafe { convert_from_jsval(cx, val, ToNumber) } } } @@ -257,7 +256,8 @@ impl FromJSValConvertible for DOMString { if nullBehavior == Empty && value.is_null() { Ok("".to_string()) } else { - let jsstr = unsafe { JS_ValueToString(cx, value) }; + let valhandle = value_handle(&value); + let jsstr = unsafe { ToString(cx, valhandle) }; if jsstr.is_null() { debug!("JS_ValueToString failed"); Err(()) @@ -285,7 +285,8 @@ impl ToJSValConvertible for ByteString { impl FromJSValConvertible<()> for ByteString { fn from_jsval(cx: *mut JSContext, value: JSVal, _option: ()) -> Result { unsafe { - let string = JS_ValueToString(cx, value); + let valhandle = value_handle(&value); + let string = ToString(cx, valhandle); if string.is_null() { debug!("JS_ValueToString failed"); return Err(()); @@ -310,7 +311,7 @@ impl ToJSValConvertible for Reflector { let obj = self.get_jsobject(); assert!(obj.is_not_null()); let mut value = ObjectValue(unsafe { &*obj }); - if unsafe { JS_WrapValue(cx, &mut value) } == 0 { + if unsafe { !JS_WrapValue(cx, mut_value_handle(&mut value)) } { fail!("JS_WrapValue failed."); } value @@ -369,10 +370,6 @@ impl> FromJSValConvertible<()> f impl ToJSValConvertible for *mut JSObject { fn to_jsval(&self, cx: *mut JSContext) -> JSVal { - let mut wrapped = ObjectOrNullValue(*self); - unsafe { - assert!(JS_WrapValue(cx, &mut wrapped) != 0); - } - wrapped + ObjectOrNullValue(*self).to_jsval(cx) } } diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs index e2e06d8205af..f23a9a23d030 100644 --- a/components/script/dom/bindings/error.rs +++ b/components/script/dom/bindings/error.rs @@ -6,11 +6,12 @@ use dom::bindings::conversions::ToJSValConvertible; use dom::bindings::global::GlobalRef; +use dom::bindings::utils::value_handle; use dom::domexception::DOMException; -use js::jsapi::{JSContext, JSBool, JSObject}; +use js::jsapi::{JSContext, JSObject}; use js::jsapi::{JS_IsExceptionPending, JS_SetPendingException, JS_ReportPendingException}; -use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR}; +use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, Struct_JSErrorFormatString, JSEXN_TYPEERR}; use js::jsapi::{JS_SaveFrameChain, JS_RestoreFrameChain}; use js::glue::{ReportError}; use js::rust::with_compartment; @@ -47,23 +48,23 @@ pub type ErrorResult = Fallible<()>; /// Set a pending DOM exception for the given `result` on `cx`. pub fn throw_dom_exception(cx: *mut JSContext, global: &GlobalRef, result: Error) { - assert!(unsafe { JS_IsExceptionPending(cx) } == 0); + assert!(unsafe { !JS_IsExceptionPending(cx) }); let exception = DOMException::new_from_error(global, result).root(); let thrown = exception.to_jsval(cx); unsafe { - JS_SetPendingException(cx, thrown); + JS_SetPendingException(cx, value_handle(&thrown)); } } /// Report a pending exception, thereby clearing it. pub fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) { unsafe { - if JS_IsExceptionPending(cx) != 0 { + if JS_IsExceptionPending(cx) { let saved = JS_SaveFrameChain(cx); with_compartment(cx, obj, || { JS_ReportPendingException(cx); }); - if saved != 0 { + if saved { JS_RestoreFrameChain(cx); } } @@ -72,13 +73,13 @@ pub fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) { /// Throw an exception to signal that a `JSVal` can not be converted to any of /// the types in an IDL union type. -pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) -> JSBool { - assert!(unsafe { JS_IsExceptionPending(cx) } == 0); +pub fn throw_not_in_union(cx: *mut JSContext, names: &'static str) -> bool { + assert!(unsafe { !JS_IsExceptionPending(cx) }); let message = format!("argument could not be converted to any of: {}", names); message.with_c_str(|string| { unsafe { ReportError(cx, string) }; }); - return 0; + return false; } /// Format string used to throw `TypeError`s. @@ -89,8 +90,7 @@ static ERROR_FORMAT_STRING_STRING: [libc::c_char, ..4] = [ 0 as libc::c_char, ]; -/// Format string struct used to throw `TypeError`s. -static ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString { +static ERROR_FORMAT_STRING: JSErrorFormatString = Struct_JSErrorFormatString { format: &ERROR_FORMAT_STRING_STRING as *const libc::c_char, argCount: 1, exnType: JSEXN_TYPEERR as i16, diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs index a0521b17535c..fafed39be90e 100644 --- a/components/script/dom/bindings/js.rs +++ b/components/script/dom/bindings/js.rs @@ -49,13 +49,19 @@ use dom::bindings::utils::{Reflector, Reflectable}; use dom::node::Node; use dom::xmlhttprequest::{XMLHttpRequest, TrustedXHRAddress}; use dom::worker::{Worker, TrustedWorkerAddress}; -use js::jsapi::JSObject; +use js::{ContextFriendFields, THING_ROOT_OBJECT}; +use js::glue::{insertObjectLinkedListElement, getPersistentRootedObjectList}; +use js::glue::{objectIsPoisoned, objectRelocate, objectNeedsPostBarrier, objectPostBarrier}; +use js::jsapi::{JSContext, JSObject, JS_IsInRequest, JS_GetRuntime}; use layout_interface::TrustedNodeAddress; use script_task::StackRoots; +use libc; use std::cell::{Cell, RefCell}; +use std::default::Default; use std::kinds::marker::ContravariantLifetime; use std::mem; +use std::ptr; /// A type that represents a JS-owned value that is rooted for the lifetime of this value. /// Importantly, it requires explicit rooting in order to interact with the inner value. @@ -64,8 +70,53 @@ use std::mem; #[allow(unrooted_must_root)] pub struct Temporary { inner: JS, - /// On-stack JS pointer to assuage conservative stack scanner - _js_ptr: *mut JSObject, + js_ptr: Box, +} + +struct PersistentRootedObjectElement { + next: *mut PersistentRootedObjectElement, + prev: *mut PersistentRootedObjectElement, + isSentinel: bool, + ptr: *mut JSObject, +} + +impl PersistentRootedObjectElement { + fn new(ptr: *mut JSObject) -> PersistentRootedObjectElement { + PersistentRootedObjectElement { + next: ptr::null_mut(), + prev: ptr::null_mut(), + isSentinel: false, + ptr: ptr, + } + } + + fn init(&mut self) { + assert!(self.next.is_null()); + assert!(self.prev.is_null()); + let roots = StackRoots.get().unwrap(); + let rt = unsafe { JS_GetRuntime((**roots).cx) }; + self.next = self as *mut _; + self.prev = self as *mut _; + unsafe { + let list = getPersistentRootedObjectList(rt); + insertObjectLinkedListElement(list, self as *mut _ as *mut _); + } + } +} + +impl Drop for PersistentRootedObjectElement { + fn drop(&mut self) { + assert!(!self.next.is_null()); + assert!(!self.prev.is_null()); + if self.next != self as *mut _ { + unsafe { + (*self.prev).next = self.next; + (*self.next).prev = self.prev; + self.next = self as *mut _; + self.prev = self as *mut _; + } + } + } } impl PartialEq for Temporary { @@ -77,9 +128,12 @@ impl PartialEq for Temporary { impl Temporary { /// Create a new `Temporary` value from a JS-owned value. pub fn new(inner: JS) -> Temporary { + let mut js_ptr = + box PersistentRootedObjectElement::new(inner.reflector().get_jsobject()); + js_ptr.init(); Temporary { inner: inner, - _js_ptr: inner.reflector().get_jsobject(), + js_ptr: js_ptr, } } @@ -187,7 +241,7 @@ impl, U: Reflectable> JS { impl Reflectable for JS { fn reflector<'a>(&'a self) -> &'a Reflector { unsafe { - (*self.unsafe_get()).reflector() + (*self.ptr).reflector() } } } @@ -196,29 +250,94 @@ impl JS { /// Returns an unsafe pointer to the interior of this JS object without touching the borrow /// flags. This is the only method that be safely accessed from layout. (The fact that this /// is unsafe is what necessitates the layout wrappers.) - pub unsafe fn unsafe_get(&self) -> *mut T { - mem::transmute_copy(&self.ptr) + pub unsafe fn unsafe_get(&self) -> *const T { + self.ptr + } +} + +impl JS { + //XXXjdm It would be lovely if this could be private. + pub unsafe fn transmute_copy(&self) -> JS { + mem::transmute_copy(self) + } +} + +/// A mutable JS<T> value, with nullability represented by an enclosing +/// Option wrapper. Must be used in place of traditional internal mutability +/// to ensure that the proper GC barriers are enforced. +#[jstraceable] +pub struct MutNullableJS { + ptr: Cell>> +} + +impl, U: Reflectable> MutNullableJS { + pub fn new(initial: Option) -> MutNullableJS { + MutNullableJS { + ptr: Cell::new(initial.map(|initial| unsafe { initial.get_js() })) + } } +} +impl Default for MutNullableJS { + fn default() -> MutNullableJS { + MutNullableJS { + ptr: Cell::new(None::>) + } + } +} + +impl MutNullableJS { /// Store an unrooted value in this field. This is safe under the assumption that JS /// values are only used as fields in DOM types that are reachable in the GC graph, /// so this unrooted value becomes transitively rooted for the lifetime of its new owner. - pub fn assign(&mut self, val: Temporary) { - *self = unsafe { val.inner() }; + pub fn assign>(&self, val: Option) { + let reflector = val.as_ref() + .map(|val| unsafe { val.get_js() }.reflector().get_jsobject()) + .unwrap_or(ptr::null_mut()); + unsafe { + assert!(!objectIsPoisoned(reflector)); + } + if unsafe { objectNeedsPostBarrier(reflector) } { + self.ptr.set(val.as_ref().map(|val| unsafe { val.get_js() })); + let raw_ptr = self.ptr.get() + .map(|val| val.reflector().rootable()) + .unwrap_or(ptr::null_mut()); + unsafe { + objectPostBarrier(raw_ptr); + } + } else if unsafe { objectNeedsPostBarrier(self.ptr + .get() + .map(|val| val.reflector().get_jsobject()) + .unwrap_or(ptr::null_mut())) } { + let raw_ptr = self.ptr.get() + .map(|val| val.reflector().rootable()) + .unwrap_or(ptr::null_mut()); + unsafe { + objectRelocate(raw_ptr); + self.ptr.set(val.map(|val| unsafe { val.get_js() })); + } + } else { + self.ptr.set(val.map(|val| unsafe { val.get_js() })); + } } -} -impl JS { - //XXXjdm It would be lovely if this could be private. - pub unsafe fn transmute(self) -> JS { - mem::transmute(self) + /// Set the inner value to null, without making API users jump through useless + /// type-ascription hoops. + pub fn clear(&self) { + self.assign(None::>); } - pub unsafe fn transmute_copy(&self) -> JS { - mem::transmute_copy(self) + /// Retrieve a copy of the current optional inner value. + pub fn get(&self) -> Option> { + self.ptr.get().map(|inner| Temporary::new(inner)) } -} + /// Retrieve a copy of the inner optional JS<T>. For use by layout, which + /// can't use safe types like Temporary. + pub unsafe fn get_inner(&self) -> Option> { + self.ptr.get() + } +} /// Get an `Option>` out of an `Option>` pub trait RootedReference { @@ -245,7 +364,7 @@ impl<'a, 'b, T: Reflectable> OptionalRootedReference for Option` value from a variety of rooting-related containers, /// which in general is an unsafe operation since they can outlive the rooted lifetime of the /// original value. -/*definitely not public*/ trait Assignable { +pub trait Assignable { unsafe fn get_js(&self) -> JS; } @@ -363,13 +482,15 @@ impl, U: Reflectable> TemporaryPushable for Vec> { /// An opaque, LIFO rooting mechanism. pub struct RootCollection { roots: RefCell>, + cx: *mut JSContext, } impl RootCollection { /// Create an empty collection of roots - pub fn new() -> RootCollection { + pub fn new(cx: *mut JSContext) -> RootCollection { RootCollection { roots: RefCell::new(vec!()), + cx: cx, } } @@ -401,12 +522,15 @@ impl RootCollection { /// Attempts to transfer ownership of a `Root` via moving will trigger dynamic unrooting /// failures due to incorrect ordering. pub struct Root<'a, 'b, T> { + stack: Cell<*mut *const *const libc::c_void>, + prev: Cell<*const *const libc::c_void>, + js_ptr: *mut JSObject, + /// Pointer to underlying Rust data + ptr: *const T, /// List that ensures correct dynamic root ordering root_list: &'a RootCollection, /// Reference to rooted value that must not outlive this container jsref: JSRef<'b, T>, - /// On-stack JS pointer to assuage conservative stack scanner - js_ptr: *mut JSObject, } impl<'b, 'a: 'b, T: Reflectable> Root<'a, 'b, T> { @@ -415,20 +539,36 @@ impl<'b, 'a: 'b, T: Reflectable> Root<'a, 'b, T> { /// which cannot outlive this new `Root`. fn new(roots: &'a RootCollection, unrooted: &JS) -> Root<'a, 'b, T> { let root = Root { + stack: Cell::new(ptr::null_mut()), + prev: Cell::new(ptr::null()), root_list: roots, jsref: JSRef { ptr: unrooted.ptr.clone(), chain: ContravariantLifetime, }, + ptr: unrooted.ptr, js_ptr: unrooted.reflector().get_jsobject(), }; roots.root(&root); root } + pub fn init(&self) { + unsafe { + assert!(JS_IsInRequest(JS_GetRuntime(self.root_list.cx))); + let cxfields: *mut ContextFriendFields = mem::transmute(self.root_list.cx); + self.stack.set(&mut (*cxfields).thingGCRooters[THING_ROOT_OBJECT as uint]); + self.prev.set(*self.stack.get()); + *self.stack.get() = self as *const Root as *const *const libc::c_void; + } + } + /// Obtain a safe reference to the wrapped JS owned-value that cannot outlive /// the lifetime of this root. pub fn root_ref<'b>(&'b self) -> JSRef<'b,T> { + if self.stack.get() == ptr::null_mut() { + self.init(); + } self.jsref.clone() } } @@ -436,12 +576,20 @@ impl<'b, 'a: 'b, T: Reflectable> Root<'a, 'b, T> { #[unsafe_destructor] impl<'b, 'a: 'b, T: Reflectable> Drop for Root<'a, 'b, T> { fn drop(&mut self) { + unsafe { + assert!(self.stack.get() != ptr::null_mut(), "Uninitialized root encountered"); + assert!(*self.stack.get() == self as *mut Root as *const *const libc::c_void); + *self.stack.get() = self.prev.get(); + } self.root_list.unroot(self); } } impl<'b, 'a: 'b, T: Reflectable> Deref> for Root<'a, 'b, T> { fn deref<'c>(&'c self) -> &'c JSRef<'b, T> { + if self.stack.get() == ptr::null_mut() { + self.init(); + } &self.jsref } } diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs index 3c26206c373e..79b6d55ab926 100644 --- a/components/script/dom/bindings/proxyhandler.rs +++ b/components/script/dom/bindings/proxyhandler.rs @@ -5,12 +5,13 @@ ///! Utilities for the implementation of JSAPI proxy handlers. 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 dom::bindings::utils::{object_handle, mut_object_handle, mut_handle}; +use js::jsapi::{JSContext, JSPropertyDescriptor, JSObject, JSString, jschar}; use js::jsapi::{JS_GetPropertyDescriptorById, JS_NewUCString, JS_malloc, JS_free}; -use js::jsapi::{JS_DefinePropertyById, JS_NewObjectWithGivenProto}; -use js::jsapi::{JS_ReportErrorFlagsAndNumber, JS_StrictPropertyStub}; +use js::jsapi::{JS_DefinePropertyById, JS_NewObjectWithGivenProto, MutableHandle}; +use js::jsapi::{JS_StrictPropertyStub, JSHandleObject, JSHandleId}; use js::jsapi::{JSREPORT_WARNING, JSREPORT_STRICT, JSREPORT_STRICT_MODE_ERROR}; +use js::jsapi::{JS_ReportErrorFlagsAndNumber}; use js::jsval::ObjectValue; use js::glue::GetProxyExtra; use js::glue::{GetObjectProto, GetObjectParent, SetProxyExtra, GetProxyHandler}; @@ -26,72 +27,77 @@ use std::mem::size_of; static JSPROXYSLOT_EXPANDO: u32 = 0; -pub unsafe extern fn getPropertyDescriptor(cx: *mut JSContext, proxy: *mut JSObject, - id: jsid, set: bool, - desc: *mut JSPropertyDescriptor) - -> bool { +pub unsafe extern fn getPropertyDescriptor(cx: *mut JSContext, + proxy: JSHandleObject, + id: JSHandleId, + mut desc: MutableHandle, + flags: u32) -> bool { let handler = GetProxyHandler(proxy); - if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, set, desc) { - return false; + { + let desc2 = mut_handle(&mut *desc); + if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, desc2, flags) { + return false; + } } - if (*desc).obj.is_not_null() { + if desc.obj.is_not_null() { return true; } //let proto = JS_GetPrototype(proxy); - let proto = GetObjectProto(proxy); + let mut proto = ptr::null_mut(); + assert!(GetObjectProto(cx, proxy, mut_object_handle(&mut proto))); if proto.is_null() { - (*desc).obj = ptr::null_mut(); + desc.obj = ptr::null_mut(); return true; } - JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc) != 0 + JS_GetPropertyDescriptorById(cx, object_handle(&proto), id, JSRESOLVE_QUALIFIED, desc) } -pub unsafe fn defineProperty_(cx: *mut JSContext, proxy: *mut JSObject, id: jsid, - desc: *mut JSPropertyDescriptor) -> bool { +pub unsafe fn defineProperty_(cx: *mut JSContext, proxy: JSHandleObject, id: JSHandleId, + desc: MutableHandle) -> bool { static JSMSG_GETTER_ONLY: libc::c_uint = 160; //FIXME: Workaround for https://github.com/mozilla/rust/issues/13385 - let setter: *const libc::c_void = mem::transmute((*desc).setter); + let setter: *const libc::c_void = mem::transmute(desc.setter); let setter_stub: *const libc::c_void = mem::transmute(JS_StrictPropertyStub); - if ((*desc).attrs & JSPROP_GETTER) != 0 && setter == setter_stub { + if (desc.attrs & JSPROP_GETTER) != 0 && setter == setter_stub { return JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING | JSREPORT_STRICT | JSREPORT_STRICT_MODE_ERROR, Some(RUST_js_GetErrorMessage), ptr::null_mut(), - JSMSG_GETTER_ONLY) != 0; + JSMSG_GETTER_ONLY); } - let expando = EnsureExpandoObject(cx, proxy); + let expando = EnsureExpandoObject(cx, *proxy); if expando.is_null() { return false; } - return JS_DefinePropertyById(cx, expando, id, (*desc).value, (*desc).getter, - (*desc).setter, (*desc).attrs) != 0; + return JS_DefinePropertyById(cx, expando, *id, desc.value, + desc.getter, desc.setter, desc.attrs); } -pub unsafe extern fn defineProperty(cx: *mut JSContext, proxy: *mut JSObject, id: jsid, - desc: *mut JSPropertyDescriptor) -> bool { +pub unsafe extern fn defineProperty(cx: *mut JSContext, proxy: JSHandleObject, id: JSHandleId, + desc: MutableHandle) -> bool { defineProperty_(cx, proxy, id, desc) } -pub unsafe extern fn delete_(cx: *mut JSContext, proxy: *mut JSObject, id: jsid, +pub unsafe extern fn delete_(cx: *mut JSContext, proxy: JSHandleObject, id: JSHandleId, bp: *mut bool) -> bool { - let expando = EnsureExpandoObject(cx, proxy); + let expando = EnsureExpandoObject(cx, *proxy); if expando.is_null() { return false; } - return delete_property_by_id(cx, expando, id, &mut *bp); + return delete_property_by_id(cx, object_handle(&expando), id, &mut *bp); } pub fn _obj_toString(cx: *mut JSContext, className: *const libc::c_char) -> *mut JSString { unsafe { let name = string::raw::from_buf(className as *const i8 as *const u8); let nchars = "[object ]".len() + name.len(); - let chars: *mut jschar = JS_malloc(cx, (nchars + 1) as libc::size_t * (size_of::() as libc::size_t)) as *mut jschar; + let chars = JS_malloc(cx, (nchars + 1) as libc::size_t * (size_of::() as libc::size_t)) as *mut jschar; if chars.is_null() { return ptr::null_mut(); } @@ -112,7 +118,7 @@ pub fn _obj_toString(cx: *mut JSContext, className: *const libc::c_char) -> *mut pub fn GetExpandoObject(obj: *mut JSObject) -> *mut JSObject { unsafe { - assert!(is_dom_proxy(obj)); + //XXXjdm it would be nice to assert that obj's class is a proxy class let val = GetProxyExtra(obj, JSPROXYSLOT_EXPANDO); if val.is_undefined() { ptr::null_mut() @@ -124,12 +130,12 @@ pub fn GetExpandoObject(obj: *mut JSObject) -> *mut JSObject { pub fn EnsureExpandoObject(cx: *mut JSContext, obj: *mut JSObject) -> *mut JSObject { unsafe { - assert!(is_dom_proxy(obj)); + //XXXjdm it would be nice to assert that obj's class is a proxy class let mut expando = GetExpandoObject(obj); if expando.is_null() { - expando = JS_NewObjectWithGivenProto(cx, ptr::null_mut(), - ptr::null_mut(), - GetObjectParent(obj)); + expando = JS_NewObjectWithGivenProto(cx, ptr::null(), + object_handle(&ptr::null_mut()), + object_handle(&GetObjectParent(obj))); if expando.is_null() { return ptr::null_mut(); } @@ -145,5 +151,4 @@ pub fn FillPropertyDescriptor(desc: &mut JSPropertyDescriptor, obj: *mut JSObjec desc.attrs = if readonly { JSPROP_READONLY } else { 0 } | JSPROP_ENUMERATE; desc.getter = None; desc.setter = None; - desc.shortid = 0; } diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 0d87892aecf3..4054e13df80c 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -27,12 +27,15 @@ use dom::bindings::js::JS; use dom::bindings::utils::{Reflectable, Reflector}; -use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSTRACE_OBJECT}; +use dom::eventtarget::EventTarget; + +use js::jsapi::{JSObject, JSTracer, JS_CallValueTracer, JS_CallObjectTracer}; use js::jsval::JSVal; use libc; -use std::rc::Rc; use std::cell::{Cell, RefCell}; +use std::collections::HashSet; +use std::rc::Rc; use url::Url; use servo_util::atom::Atom; @@ -58,19 +61,18 @@ pub trait JSTraceable { } /// Trace a `JSVal`. -pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: JSVal) { - if !val.is_markable() { +pub fn trace_jsval(tracer: *mut JSTracer, description: &str, orig_val: JSVal) { + if !orig_val.is_markable() { return; } + debug!("tracing value {:s}", description); + let name = description.to_c_str(); + let mut val = orig_val; unsafe { - let name = description.to_c_str(); - (*tracer).debugPrinter = None; - (*tracer).debugPrintIndex = -1; - (*tracer).debugPrintArg = name.as_ptr() as *const libc::c_void; - debug!("tracing value {:s}", description); - JS_CallTracer(tracer, val.to_gcthing(), val.trace_kind()); + JS_CallValueTracer(tracer, &mut val, name.as_ptr()); } + assert!(val == orig_val); } /// Trace the `JSObject` held by `reflector`. @@ -80,15 +82,20 @@ pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Ref } /// Trace a `JSObject`. -pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: *mut JSObject) { +pub fn trace_object(tracer: *mut JSTracer, description: &str, orig_obj: *mut JSObject) { + debug!("tracing {:s}", description); + let name = description.to_c_str(); + let mut obj = orig_obj; unsafe { - let name = description.to_c_str(); - (*tracer).debugPrinter = None; - (*tracer).debugPrintIndex = -1; - (*tracer).debugPrintArg = name.as_ptr() as *const libc::c_void; - debug!("tracing {:s}", description); - JS_CallTracer(tracer, obj as *mut libc::c_void, JSTRACE_OBJECT); + JS_CallObjectTracer(tracer, &mut obj, name.as_ptr()); } + // FIXME: JS_CallObjectTracer could theoretically do something that can + // cause pointers to shuffle around. We need to pass a *mut *mut JSObject + // to JS_CallObjectTracer, but the Encodable trait doesn't allow us + // to obtain a mutable reference to self (and thereby self.cb); + // All we can do right now is scream loudly if this actually causes + // a problem in practice. + assert!(obj == orig_obj); } /// Encapsulates a type that cannot easily have `Encodable` derived automagically, @@ -174,7 +181,6 @@ impl JSTraceable for Traceable> { } } - impl JSTraceable for Cell { fn trace(&self, trc: *mut JSTracer) { self.get().trace(trc) @@ -239,3 +245,55 @@ impl<'a> JSTraceable for &'a str { } } +#[allow(unrooted_must_root)] +#[jstraceable] +pub struct RootedVec { + v: Vec> +} + +local_data_key!(pub RootedCollections: RefCell>) + +#[unsafe_destructor] +impl Drop for RootedVec { + fn drop(&mut self) { + let collections = RootedCollections.get(); + let mut collections = collections.as_ref().unwrap().borrow_mut(); + assert!(collections.remove(&(self as *mut RootedVec as *const ()))); + } +} + +impl RootedVec { + pub fn new() -> RootedVec { + RootedVec { + v: vec!() + } + } + + pub fn init(&self) { + let collections = RootedCollections.get(); + let mut collections = collections.as_ref().unwrap().borrow_mut(); + collections.insert(self as *const RootedVec as *const ()); + } +} + +impl Deref>> for RootedVec { + fn deref<'a>(&'a self) -> &'a Vec> { + &self.v + } +} + +impl DerefMut>> for RootedVec { + fn deref_mut<'a>(&'a mut self) -> &'a mut Vec> { + &mut self.v + } +} + +pub extern fn trace_collections(tracer: *mut JSTracer, data: *mut libc::c_void) { + let collections = data as *const RefCell>>; //XXXjdm + let collections = unsafe { (*collections).borrow() }; + for collection in collections.iter() { + unsafe { + let _ = (**collection).trace(tracer); + } + } +} diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs index 1a48cfc08d2e..f7672b4c4208 100644 --- a/components/script/dom/bindings/utils.rs +++ b/components/script/dom/bindings/utils.rs @@ -4,6 +4,7 @@ //! Various utilities to glue JavaScript and the DOM implementation together. +use dom::bindings::codegen::Bindings::WindowBinding; use dom::bindings::codegen::PrototypeList; use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH; use dom::bindings::conversions::IDLInterface; @@ -22,25 +23,25 @@ use std::mem; use std::cmp::PartialEq; use std::ptr; use std::slice; -use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFamily}; -use js::glue::{UnwrapObject, GetProxyHandlerExtra}; +//use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFamily}; +//use js::glue::{UnwrapObject, GetProxyHandlerExtra}; +use js::glue::{CompartmentOptions_SetVersion, CompartmentOptions_SetTraceGlobal, UnwrapObject}; use js::glue::{IsWrapper, RUST_JSID_TO_STRING, RUST_JSID_IS_INT}; -use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_INT}; -use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewFunction}; -use js::jsapi::{JS_DefineProperties, JS_ForwardGetPropertyTo}; +use js::glue::{RUST_JSID_IS_STRING, RUST_JSID_TO_INT, ToString, NewGlobalObject}; +use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewFunction, JSVERSION_LATEST}; +use js::jsapi::{JS_DefineProperties, JS_ForwardGetPropertyTo, JSHandleValue}; use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype, JS_GetStringCharsAndLength}; -use js::jsapi::{JS_ObjectIsRegExp, JS_ObjectIsDate, JSHandleObject}; -use js::jsapi::JS_GetFunctionObject; +use js::jsapi::{JS_ObjectIsRegExp, JS_ObjectIsDate, JSHandleObject, JSMutableHandleValue}; +use js::jsapi::{JS_GetFunctionObject, JSMutableHandleObject, MutableHandle}; use js::jsapi::{JS_HasPropertyById, JS_GetPrototype}; use js::jsapi::{JS_GetProperty, JS_HasProperty}; use js::jsapi::{JS_DefineFunctions, JS_DefineProperty}; -use js::jsapi::{JS_ValueToString, JS_GetReservedSlot, JS_SetReservedSlot}; -use js::jsapi::{JSContext, JSObject, JSBool, jsid, JSClass}; -use js::jsapi::{JSFunctionSpec, JSPropertySpec}; -use js::jsapi::{JS_NewGlobalObject, JS_InitStandardClasses}; -use js::jsapi::{JSString}; +use js::jsapi::{JS_GetReservedSlot, JS_SetReservedSlot}; +use js::jsapi::{JSContext, JSObject, jsid, JSClass}; +use js::jsapi::{JSFunctionSpec, JSPropertySpec, JSHandleId}; +use js::jsapi::{JS_InitStandardClasses}; +use js::jsapi::{JSString, Handle}; use js::jsapi::JS_DeletePropertyById2; -use js::jsfriendapi::JS_ObjectToOuterObject; use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType; use js::jsval::JSVal; use js::jsval::{PrivateValue, ObjectValue, NullValue}; @@ -50,6 +51,13 @@ use js::{JSPROP_ENUMERATE, JSPROP_READONLY, JSPROP_PERMANENT}; use js::JSFUN_CONSTRUCTOR; use js; +pub type RustPropertyOp = Option bool>; +pub type RustStrictPropertyOp = Option bool>; + #[allow(raw_pointer_deriving)] #[jstraceable] pub struct GlobalStaticData { @@ -69,26 +77,10 @@ fn is_dom_class(clasp: *const JSClass) -> bool { } } -/// 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 - } + assert!(is_dom_class(clasp)); + DOM_OBJECT_SLOT as u32 } /// Get the DOM object from the given reflector. @@ -106,11 +98,6 @@ pub unsafe fn get_dom_class(obj: *mut JSObject) -> Result { 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(()); } @@ -128,7 +115,7 @@ pub fn unwrap_jsmanaged(mut obj: *mut JSObject, let dom_class = get_dom_class(obj).or_else(|_| { if IsWrapper(obj) == 1 { debug!("found wrapper"); - obj = UnwrapObject(obj, /* stopAtOuter = */ 0, ptr::null_mut()); + obj = UnwrapObject(obj, /* stopAtOuter = */ false); if obj.is_null() { debug!("unwrapping security wrapper failed"); Err(()) @@ -176,7 +163,7 @@ pub fn jsstring_to_str(cx: *mut JSContext, s: *mut JSString) -> DOMString { /// string, or if the string does not contain valid UTF-16. pub fn jsid_to_str(cx: *mut JSContext, id: jsid) -> DOMString { unsafe { - assert!(RUST_JSID_IS_STRING(id) != 0); + assert!(RUST_JSID_IS_STRING(id)); jsstring_to_str(cx, RUST_JSID_TO_STRING(id)) } } @@ -186,7 +173,10 @@ pub fn jsid_to_str(cx: *mut JSContext, id: jsid) -> DOMString { // We use slot 0 for holding the raw object. This is safe for both // globals and non-globals. pub static DOM_OBJECT_SLOT: uint = 0; -static DOM_PROXY_OBJECT_SLOT: uint = js::JSSLOT_PROXY_PRIVATE as uint; + +#[allow(dead_code)] +#[static_assert] +static DOM_SLOT_IS_PROXY_PRIVATE: bool = DOM_OBJECT_SLOT == 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 @@ -281,13 +271,13 @@ pub struct NativeProperties { /// A JSNative that cannot be null. pub type NonNullJSNative = - unsafe extern "C" fn (arg1: *mut JSContext, arg2: c_uint, arg3: *mut JSVal) -> JSBool; + unsafe extern "C" fn (arg1: *mut JSContext, arg2: c_uint, arg3: *mut JSVal) -> bool; /// Creates the *interface prototype object* and the *interface object* (if /// needed). /// Fails on JSAPI failure. -pub fn CreateInterfaceObjects2(cx: *mut JSContext, global: *mut JSObject, receiver: *mut JSObject, - protoProto: *mut JSObject, +pub fn CreateInterfaceObjects2(cx: *mut JSContext, global: JSHandleObject, receiver: *mut JSObject, + protoProto: JSHandleObject, protoClass: &'static JSClass, constructor: Option<(NonNullJSNative, &'static str, u32)>, domClass: *const DOMClass, @@ -315,7 +305,7 @@ pub fn CreateInterfaceObjects2(cx: *mut JSContext, global: *mut JSObject, receiv /// Creates the *interface object*. /// Fails on JSAPI failure. -fn CreateInterfaceObject(cx: *mut JSContext, global: *mut JSObject, receiver: *mut JSObject, +fn CreateInterfaceObject(cx: *mut JSContext, global: JSHandleObject, receiver: *mut JSObject, constructorNative: NonNullJSNative, ctorNargs: u32, proto: *mut JSObject, members: &'static NativeProperties, @@ -328,6 +318,7 @@ fn CreateInterfaceObject(cx: *mut JSContext, global: *mut JSObject, receiver: *m let constructor = JS_GetFunctionObject(fun); assert!(constructor.is_not_null()); + let constructor = object_handle(&constructor); match members.staticMethods { Some(staticMethods) => DefineMethods(cx, constructor, staticMethods), _ => (), @@ -343,30 +334,34 @@ fn CreateInterfaceObject(cx: *mut JSContext, global: *mut JSObject, receiver: *m _ => (), } + let protohandle = object_handle(&proto); if proto.is_not_null() { - assert!(JS_LinkConstructorAndPrototype(cx, constructor, proto) != 0); + assert!(JS_LinkConstructorAndPrototype(cx, constructor, protohandle)); } - let mut alreadyDefined = 0; - assert!(JS_AlreadyHasOwnProperty(cx, receiver, name, &mut alreadyDefined) != 0); + let mut alreadyDefined = false; + let receiverhandle = object_handle(&receiver); + assert!(JS_AlreadyHasOwnProperty(cx, receiverhandle, name, &mut alreadyDefined)); - if alreadyDefined == 0 { - assert!(JS_DefineProperty(cx, receiver, name, - ObjectValue(&*constructor), - None, None, 0) != 0); + let constructorhandle = ObjectValue(&**constructor); + if !alreadyDefined { + assert!(JS_DefineProperty(cx, receiverhandle, name, + value_handle(&constructorhandle), + 0, None, None)); } } } /// Defines constants on `obj`. /// Fails on JSAPI failure. -fn DefineConstants(cx: *mut JSContext, obj: *mut JSObject, constants: &'static [ConstantSpec]) { +fn DefineConstants(cx: *mut JSContext, obj: JSHandleObject, constants: &'static [ConstantSpec]) { for spec in constants.iter() { + let jsval = spec.get_value(); + let jsval = value_handle(&jsval); unsafe { - assert!(JS_DefineProperty(cx, obj, spec.name.as_ptr() as *const libc::c_char, - spec.get_value(), None, None, - JSPROP_ENUMERATE | JSPROP_READONLY | - JSPROP_PERMANENT) != 0); + assert!(JS_DefineProperty(cx, obj, spec.name.as_ptr() as *const libc::c_char, jsval, + JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT, + None, None)); } } } @@ -374,31 +369,32 @@ fn DefineConstants(cx: *mut JSContext, obj: *mut JSObject, constants: &'static [ /// Defines methods on `obj`. The last entry of `methods` must contain zeroed /// memory. /// Fails on JSAPI failure. -fn DefineMethods(cx: *mut JSContext, obj: *mut JSObject, methods: &'static [JSFunctionSpec]) { +fn DefineMethods(cx: *mut JSContext, obj: JSHandleObject, methods: &'static [JSFunctionSpec]) { unsafe { - assert!(JS_DefineFunctions(cx, obj, methods.as_ptr()) != 0); + assert!(JS_DefineFunctions(cx, obj, methods.as_ptr())); } } /// Defines attributes on `obj`. The last entry of `properties` must contain /// zeroed memory. /// Fails on JSAPI failure. -fn DefineProperties(cx: *mut JSContext, obj: *mut JSObject, properties: &'static [JSPropertySpec]) { +fn DefineProperties(cx: *mut JSContext, obj: JSHandleObject, properties: &'static [JSPropertySpec]) { unsafe { - assert!(JS_DefineProperties(cx, obj, properties.as_ptr()) != 0); + assert!(JS_DefineProperties(cx, obj, properties.as_ptr())); } } /// Creates the *interface prototype object*. /// Fails on JSAPI failure. -fn CreateInterfacePrototypeObject(cx: *mut JSContext, global: *mut JSObject, - parentProto: *mut JSObject, +fn CreateInterfacePrototypeObject(cx: *mut JSContext, global: JSHandleObject, + parentProto: JSHandleObject, protoClass: &'static JSClass, members: &'static NativeProperties) -> *mut JSObject { unsafe { - let ourProto = JS_NewObjectWithUniqueType(cx, protoClass, &*parentProto, &*global); + let ourProto = JS_NewObjectWithUniqueType(cx, protoClass, parentProto, global); assert!(ourProto.is_not_null()); + let ourProto = object_handle(&ourProto); match members.methods { Some(methods) => DefineMethods(cx, ourProto, methods), _ => (), @@ -414,15 +410,15 @@ fn CreateInterfacePrototypeObject(cx: *mut JSContext, global: *mut JSObject, _ => (), } - return ourProto; + return *ourProto.unnamed_field1; } } /// A throwing constructor, for those interfaces that have neither /// `NoInterfaceObject` nor `Constructor`. -pub unsafe extern fn ThrowingConstructor(cx: *mut JSContext, _argc: c_uint, _vp: *mut JSVal) -> JSBool { +pub unsafe extern fn ThrowingConstructor(cx: *mut JSContext, _argc: c_uint, _vp: *mut JSVal) -> bool { throw_type_error(cx, "Illegal constructor."); - return 0; + return false; } /// Construct and cache the ProtoOrIfaceArray for the given global. @@ -492,26 +488,29 @@ impl Reflector { } } -pub fn GetPropertyOnPrototype(cx: *mut JSContext, proxy: *mut JSObject, id: jsid, found: *mut bool, - vp: *mut JSVal) -> bool { +pub fn GetPropertyOnPrototype(cx: *mut JSContext, proxy: JSHandleObject, id: JSHandleId, found: *mut bool, + vp: Option) -> bool { unsafe { //let proto = GetObjectProto(proxy); - let proto = JS_GetPrototype(proxy); + let mut proto = ptr::null_mut(); + if !JS_GetPrototype(cx, proxy, mut_object_handle(&mut proto)) { + return false; + } if proto.is_null() { *found = false; return true; } - let mut hasProp = 0; - if JS_HasPropertyById(cx, proto, id, &mut hasProp) == 0 { + let mut hasProp = false; + if !JS_HasPropertyById(cx, object_handle(&proto), id, &mut hasProp) { return false; } - *found = hasProp != 0; - let no_output = vp.is_null(); - if hasProp == 0 || no_output { + *found = hasProp; + let no_output = vp.as_ref().map_or(true, |vp| vp.deref().is_null()); + if !hasProp || no_output { return true; } - JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp) != 0 + JS_ForwardGetPropertyTo(cx, object_handle(&proto), id, proxy, vp.unwrap()) } } @@ -519,7 +518,7 @@ pub fn GetPropertyOnPrototype(cx: *mut JSContext, proxy: *mut JSObject, id: jsid /// `jsid` is not an integer. pub fn GetArrayIndexFromId(_cx: *mut JSContext, id: jsid) -> Option { unsafe { - if RUST_JSID_IS_INT(id) != 0 { + if RUST_JSID_IS_INT(id) { return Some(RUST_JSID_TO_INT(id) as u32); } return None; @@ -547,7 +546,8 @@ pub fn FindEnumStringIndex(cx: *mut JSContext, v: JSVal, values: &[&'static str]) -> Result, ()> { unsafe { - let jsstr = JS_ValueToString(cx, v); + let v = value_handle(&v); + let jsstr = ToString(cx, v); if jsstr.is_null() { return Err(()); } @@ -571,72 +571,84 @@ pub fn FindEnumStringIndex(cx: *mut JSContext, /// Returns `Err(())` on JSAPI failure (there is a pending exception), and /// `Ok(None)` if there was no property with the given name. pub fn get_dictionary_property(cx: *mut JSContext, - object: *mut JSObject, + object: JSHandleObject, property: &str) -> Result, ()> { use std::c_str::CString; - fn has_property(cx: *mut JSContext, object: *mut JSObject, property: &CString, - found: &mut JSBool) -> bool { - unsafe { - JS_HasProperty(cx, object, property.as_ptr(), found) != 0 + fn has_property(cx: *mut JSContext, object: JSHandleObject, + property: &CString) -> Result { + let mut found = false; + if unsafe { JS_HasProperty(cx, object, property.as_ptr(), &mut found) } { + Ok(found) + } else { + Err(()) } } - fn get_property(cx: *mut JSContext, object: *mut JSObject, property: &CString, - value: &mut JSVal) -> bool { + /*fn get_property(cx: *mut JSContext, object: JSHandleObject, property: &CString, + value: JSMutableHandleValue) -> bool { unsafe { JS_GetProperty(cx, object, property.as_ptr(), value) != 0 } - } + }*/ let property = property.to_c_str(); - if object.is_null() { + if unsafe { (*object.unnamed_field1).is_null() } { return Ok(None); } - let mut found: JSBool = 0; - if !has_property(cx, object, &property, &mut found) { - return Err(()); - } - - if found == 0 { + let found = try!(has_property(cx, object, &property)); + if !found { return Ok(None); } let mut value = NullValue(); - if !get_property(cx, object, &property, &mut value) { + /*if !get_property(cx, object, &property, mut_value_handle(&mut value)) { + return Err(()); + }*/ + if unsafe { + property.with_ref(|s| { + !JS_GetProperty(cx, object, s, mut_value_handle(&mut value)) + }) + } { return Err(()); } Ok(Some(value)) } -pub fn HasPropertyOnPrototype(cx: *mut JSContext, proxy: *mut JSObject, id: jsid) -> bool { +pub fn HasPropertyOnPrototype(cx: *mut JSContext, proxy: JSHandleObject, id: JSHandleId) -> bool { // MOZ_ASSERT(js::IsProxy(proxy) && js::GetProxyHandler(proxy) == handler); let mut found = false; - return !GetPropertyOnPrototype(cx, proxy, id, &mut found, ptr::null_mut()) || found; + return !GetPropertyOnPrototype(cx, proxy, id, &mut found, None) || found; } /// Returns whether `obj` can be converted to a callback interface per IDL. pub fn IsConvertibleToCallbackInterface(cx: *mut JSContext, obj: *mut JSObject) -> bool { unsafe { - JS_ObjectIsDate(cx, obj) == 0 && JS_ObjectIsRegExp(cx, obj) == 0 + let obj = object_handle(&obj); + !JS_ObjectIsDate(cx, obj) && !JS_ObjectIsRegExp(cx, obj) } } /// Create a DOM global object with the given class. pub fn CreateDOMGlobal(cx: *mut JSContext, class: *const JSClass) -> *mut JSObject { unsafe { - let obj = JS_NewGlobalObject(cx, class, ptr::null_mut()); + //XXXjdm need to trace the protoiface cache, too + let obj = NewGlobalObject(cx, class, ptr::null_mut(), 0 /*FireOnNewGlobalHook*/); if obj.is_null() { return ptr::null_mut(); } with_compartment(cx, obj, || { - JS_InitStandardClasses(cx, obj); + let globhandle = object_handle(&obj); + CompartmentOptions_SetVersion(cx, JSVERSION_LATEST); + CompartmentOptions_SetTraceGlobal(cx, Some(WindowBinding::_trace)); + JS_InitStandardClasses(cx, globhandle); }); initialize_global(obj); obj } } +/* /// Callback to outerize windows when wrapping. pub unsafe extern fn wrap_for_same_compartment(cx: *mut JSContext, obj: *mut JSObject) -> *mut JSObject { JS_ObjectToOuterObject(cx, obj) @@ -647,30 +659,29 @@ pub unsafe extern fn pre_wrap(cx: *mut JSContext, _scope: *mut JSObject, obj: *mut JSObject, _flags: c_uint) -> *mut JSObject { JS_ObjectToOuterObject(cx, obj) } +*/ /// Callback to outerize windows. -pub extern fn outerize_global(_cx: *mut JSContext, obj: JSHandleObject) -> *mut JSObject { - unsafe { - debug!("outerizing"); - let obj = *obj.unnamed_field1; - let win: Root = - unwrap_jsmanaged(obj, - IDLInterface::get_prototype_id(None::), - IDLInterface::get_prototype_depth(None::)) - .unwrap() - .root(); - win.deref().browser_context.deref().borrow().as_ref().unwrap().window_proxy() - } -} - -pub unsafe fn delete_property_by_id(cx: *mut JSContext, object: *mut JSObject, - id: jsid, bp: &mut bool) -> bool { - let mut value = UndefinedValue(); - if JS_DeletePropertyById2(cx, object, id, &mut value) == 0 { +pub unsafe extern fn outerize_global(_cx: *mut JSContext, obj: JSHandleObject) -> *mut JSObject { + debug!("outerizing"); + let obj = *obj.unnamed_field1; + let win: Root = + unwrap_jsmanaged(obj, + IDLInterface::get_prototype_id(None::), + IDLInterface::get_prototype_depth(None::)) + .unwrap() + .root(); + win.deref().browser_context.deref().borrow().as_ref().unwrap().window_proxy() +} + +pub unsafe fn delete_property_by_id(cx: *mut JSContext, object: JSHandleObject, + id: JSHandleId, bp: &mut bool) -> bool { + let mut found = false; + if !JS_DeletePropertyById2(cx, object, id, &mut found) { return false; } - *bp = value.to_boolean(); + *bp = found; return true; } @@ -751,3 +762,39 @@ pub fn xml_name_type(name: &str) -> XMLName { true => Name } } + +pub fn object_handle<'a>(obj: &'a *mut JSObject) -> JSHandleObject<'a> { + Handle { + unnamed_field1: obj + } +} + +pub fn mut_object_handle<'a>(obj: &'a mut *mut JSObject) -> JSMutableHandleObject<'a> { + MutableHandle { + unnamed_field1: obj + } +} + +pub fn id_handle<'a>(id: &'a jsid) -> JSHandleId<'a> { + Handle { + unnamed_field1: id + } +} + +pub fn value_handle<'a>(val: &'a JSVal) -> JSHandleValue<'a> { + Handle { + unnamed_field1: val + } +} + +pub fn mut_value_handle<'a>(val: &'a mut JSVal) -> JSMutableHandleValue<'a> { + MutableHandle { + unnamed_field1: val + } +} + +pub fn mut_handle<'a, T>(val: &'a mut T) -> MutableHandle<'a, T> { + MutableHandle { + unnamed_field1: val + } +} diff --git a/components/script/dom/browsercontext.rs b/components/script/dom/browsercontext.rs index 927078d4d302..052ad6823d09 100644 --- a/components/script/dom/browsercontext.rs +++ b/components/script/dom/browsercontext.rs @@ -4,14 +4,25 @@ use dom::bindings::js::{JS, JSRef, Temporary}; use dom::bindings::trace::Traceable; -use dom::bindings::utils::Reflectable; +use dom::bindings::utils::{Reflectable, object_handle}; use dom::document::Document; use dom::window::Window; -use js::jsapi::JSObject; -use js::glue::{WrapperNew, CreateWrapperProxyHandler, ProxyTraps}; +use js; +use js::jsapi::{JSObject, JS_PropertyStub, JS_StrictPropertyStub, JS_DeletePropertyStub}; +use js::jsapi::{JS_EnumerateStub, JS_ResolveStub, JSFunctionSpec}; +use js::jsval::PrivateValue; +use js::glue::{WrapperNew, CreateWrapperProxyHandler, ProxyTraps, SetProxyExtra}; +use js::glue::{proxy_LookupGeneric, proxy_LookupProperty, proxy_LookupElement}; +use js::glue::{proxy_DefineGeneric, proxy_DefineProperty, proxy_DefineElement}; +use js::glue::{proxy_GetGeneric, proxy_SetGeneric, proxy_SetProperty, proxy_SetElement}; +use js::glue::{proxy_GetGenericAttributes, proxy_SetGenericAttributes, proxy_DeleteProperty}; +use js::glue::{proxy_DeleteElement, proxy_Trace, proxy_WeakmapKeyDelegate, proxy_Finalize}; +use js::glue::{proxy_HasInstance, proxy_innerObject, proxy_Watch}; +use js::glue::{proxy_Unwatch, proxy_Slice, proxy_Convert, proxy_GetProperty, proxy_GetElement}; use js::rust::with_compartment; +use libc; use libc::c_void; use std::ptr; @@ -56,16 +67,80 @@ impl BrowserContext { let handler = js_info.as_ref().unwrap().dom_static.windowproxy_handler; assert!(handler.deref().is_not_null()); - let parent = win.deref().reflector().get_jsobject(); + let obj = win.deref().reflector().get_jsobject(); let cx = js_info.as_ref().unwrap().js_context.deref().deref().ptr; - let wrapper = with_compartment(cx, parent, || unsafe { - WrapperNew(cx, parent, *handler.deref()) + let wrapper = with_compartment(cx, obj, || unsafe { + WrapperNew(cx, object_handle(&obj), object_handle(&obj), *handler.deref(), + &mut ProxyClass, true) }); assert!(wrapper.is_not_null()); + unsafe { + SetProxyExtra(wrapper, 0, PrivateValue(obj as *const libc::c_void)); + } self.window_proxy = Traceable::new(wrapper); } } +static proxy_name: [u8, ..6] = ['P' as u8, 'r' as u8, 'o' as u8, 'x' as u8, 'y' as u8, 0]; +static mut ProxyClass: js::Class = js::Class { + name: &proxy_name as *const u8 as *const libc::c_char, + flags: js::NON_NATIVE | js::JSCLASS_IS_PROXY | js::JSCLASS_IMPLEMENTS_BARRIERS | + ((js::PROXY_MINIMUM_SLOTS & js::JSCLASS_RESERVED_SLOTS_MASK as u32) << js::JSCLASS_RESERVED_SLOTS_SHIFT), + addProperty: Some(JS_PropertyStub), + delProperty: Some(JS_DeletePropertyStub), + getProperty: Some(JS_PropertyStub), + setProperty: Some(JS_StrictPropertyStub), + enumerate: Some(JS_EnumerateStub), + resolve: Some(JS_ResolveStub), + convert: Some(proxy_Convert), + finalize: Some(proxy_Finalize), + call: None, + hasInstance: Some(proxy_HasInstance), + construct: None, + trace: Some(proxy_Trace), + + spec: js::ClassSpec { + createConstructor: None, + createPrototype: None, + constructorFunctions: 0 as *const JSFunctionSpec, + prototypeFunctions: 0 as *const JSFunctionSpec, + finishInit: None, + }, + + ext: js::ClassExtension { + outerObject: None, + innerObject: Some(proxy_innerObject), + iteratorObject: 0 as *const u8, + isWrappedNative: false, + weakmapKeyDelegateOp: Some(proxy_WeakmapKeyDelegate), + }, + + ops: js::ObjectOps { + lookupGeneric: Some(proxy_LookupGeneric), + lookupProperty: Some(proxy_LookupProperty), + lookupElement: Some(proxy_LookupElement), + defineGeneric: Some(proxy_DefineGeneric), + defineProperty: Some(proxy_DefineProperty), + defineElement: Some(proxy_DefineElement), + getGeneric: Some(proxy_GetGeneric), + getProperty: Some(proxy_GetProperty), + getElement: Some(proxy_GetElement), + setGeneric: Some(proxy_SetGeneric), + setProperty: Some(proxy_SetProperty), + setElement: Some(proxy_SetElement), + getGenericAttributes: Some(proxy_GetGenericAttributes), + setGenericAttributes: Some(proxy_SetGenericAttributes), + deleteProperty: Some(proxy_DeleteProperty), + deleteElement: Some(proxy_DeleteElement), + watch: Some(proxy_Watch), + unwatch: Some(proxy_Unwatch), + slice: Some(proxy_Slice), + + enumerate: 0 as *const u8, + thisObject: None, + }, +}; + #[jstraceable] #[must_root] pub struct SessionHistoryEntry { @@ -83,6 +158,7 @@ impl SessionHistoryEntry { } static proxy_handler: ProxyTraps = ProxyTraps { + preventExtensions: None, getPropertyDescriptor: None, getOwnPropertyDescriptor: None, defineProperty: None, @@ -97,19 +173,16 @@ static proxy_handler: ProxyTraps = ProxyTraps { keys: 0 as *const u8, iterate: None, + isExtensible: None, call: None, construct: None, nativeCall: 0 as *const u8, hasInstance: None, - typeOf: None, objectClassIs: None, - obj_toString: None, fun_toString: None, - //regexp_toShared: 0 as *u8, + //regexp_toShared: 0 as *const u8, defaultValue: None, - iteratorNext: None, finalize: None, - getElementIfPresent: None, getPrototypeOf: None, trace: None }; diff --git a/components/script/dom/dedicatedworkerglobalscope.rs b/components/script/dom/dedicatedworkerglobalscope.rs index d043bde2b620..742c977760cd 100644 --- a/components/script/dom/dedicatedworkerglobalscope.rs +++ b/components/script/dom/dedicatedworkerglobalscope.rs @@ -10,7 +10,7 @@ use dom::bindings::codegen::InheritTypes::{EventTargetCast, WorkerGlobalScopeCas use dom::bindings::global; use dom::bindings::js::{JSRef, Temporary, RootCollection}; use dom::bindings::trace::Untraceable; -use dom::bindings::utils::{Reflectable, Reflector}; +use dom::bindings::utils::{Reflectable, Reflector, mut_value_handle, value_handle}; use dom::eventtarget::{EventTarget, EventTargetHelpers}; use dom::eventtarget::WorkerGlobalScopeTypeId; use dom::messageevent::MessageEvent; @@ -26,7 +26,8 @@ use script_task::StackRootTLS; use servo_net::resource_task::{ResourceTask, load_whole_resource}; use js::glue::JS_STRUCTURED_CLONE_VERSION; -use js::jsapi::{JSContext, JS_ReadStructuredClone, JS_WriteStructuredClone}; +use js::jsapi::JSContext; +use js::jsfriendapi::{JS_ReadStructuredClone, JS_WriteStructuredClone}; use js::jsval::{JSVal, UndefinedValue}; use js::rust::Cx; @@ -91,8 +92,6 @@ impl DedicatedWorkerGlobalScope { .native() .named(format!("Web Worker at {}", worker_url.serialize())) .spawn(proc() { - let roots = RootCollection::new(); - let _stack_roots_tls = StackRootTLS::new(&roots); let (url, source) = match load_whole_resource(&resource_task, worker_url.clone()) { Err(_) => { @@ -105,6 +104,9 @@ impl DedicatedWorkerGlobalScope { }; let (_js_runtime, js_context) = ScriptTask::new_rt_and_cx(); + let roots = RootCollection::new(js_context.ptr); + let _stack_roots_tls = StackRootTLS::new(&roots); + let global = DedicatedWorkerGlobalScope::new( worker_url, worker, js_context.clone(), resource_task, parent_sender, own_sender, receiver).root(); @@ -126,8 +128,8 @@ impl DedicatedWorkerGlobalScope { unsafe { assert!(JS_ReadStructuredClone( js_context.ptr, data as *const u64, nbytes, - JS_STRUCTURED_CLONE_VERSION, &mut message, - ptr::null(), ptr::null_mut()) != 0); + JS_STRUCTURED_CLONE_VERSION, mut_value_handle(&mut message), + ptr::null(), ptr::null_mut())); } MessageEvent::dispatch_jsval(target, &global::Worker(scope), message); @@ -154,9 +156,11 @@ impl<'a> DedicatedWorkerGlobalScopeMethods for JSRef<'a, DedicatedWorkerGlobalSc fn PostMessage(self, cx: *mut JSContext, message: JSVal) { let mut data = ptr::null_mut(); let mut nbytes = 0; + let transferable = UndefinedValue(); unsafe { - assert!(JS_WriteStructuredClone(cx, message, &mut data, &mut nbytes, - ptr::null(), ptr::null_mut()) != 0); + assert!(JS_WriteStructuredClone(cx, value_handle(&message), &mut data, &mut nbytes, + ptr::null(), ptr::null_mut(), + value_handle(&transferable))); } let ScriptChan(ref sender) = self.parent_sender; diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 63f205206fa2..e8fceaaf35c1 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -21,8 +21,8 @@ use dom::bindings::error::{ErrorResult, Fallible, NotSupported, InvalidCharacter use dom::bindings::error::{HierarchyRequest, NamespaceError}; use dom::bindings::global::GlobalRef; use dom::bindings::global; -use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable, TemporaryPushable}; -use dom::bindings::js::OptionalRootable; +use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, OptionalSettable}; +use dom::bindings::js::{TemporaryPushable, OptionalRootable}; use dom::bindings::trace::{Traceable, Untraceable}; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::bindings::utils::{xml_name_type, InvalidXMLName, Name, QName}; @@ -32,7 +32,7 @@ use dom::documentfragment::DocumentFragment; use dom::documenttype::DocumentType; use dom::domimplementation::DOMImplementation; use dom::element::{Element, AttributeHandlers, get_attribute_parts}; -use dom::element::{HTMLHtmlElementTypeId, HTMLHeadElementTypeId, HTMLTitleElementTypeId}; +use dom::element::{HTMLHeadElementTypeId, HTMLTitleElementTypeId}; use dom::element::{HTMLBodyElementTypeId, HTMLFrameSetElementTypeId}; use dom::event::Event; use dom::eventtarget::{EventTarget, NodeTargetTypeId, EventTargetHelpers}; @@ -60,10 +60,12 @@ use servo_util::namespace; use servo_util::namespace::{Namespace, Null}; use servo_util::str::{DOMString, split_html_space_chars}; +use url::Url; + use std::collections::hashmap::HashMap; use std::ascii::StrAsciiExt; use std::cell::{Cell, RefCell}; -use url::Url; +use std::default::Default; use time; #[deriving(PartialEq)] @@ -80,7 +82,7 @@ pub struct Document { reflector_: Reflector, pub window: JS, idmap: Traceable>>>>, - implementation: Cell>>, + implementation: MutNullableJS, content_type: DOMString, last_modified: Traceable>>, pub encoding_name: Traceable>, @@ -242,6 +244,7 @@ impl<'a> DocumentHelpers<'a> for JSRef<'a, Document> { // FIXME https://github.com/mozilla/rust/issues/13195 // Use mangle() when it exists again. let root = self.GetDocumentElement().expect("The element is in the document, so there must be a document element.").root(); + root.init(); match idmap.find_mut(&id) { Some(elements) => { let new_node: JSRef = NodeCast::from_ref(element); @@ -289,7 +292,7 @@ impl Document { reflector_: Reflector::new(), window: JS::from_rooted(window), idmap: Traceable::new(RefCell::new(HashMap::new())), - implementation: Cell::new(None), + implementation: Default::default(), content_type: match content_type { Some(string) => string.clone(), None => match is_html_document { @@ -346,6 +349,7 @@ trait PrivateDocumentHelpers { impl<'a> PrivateDocumentHelpers for JSRef<'a, Document> { fn createNodeList(self, callback: |node: JSRef| -> bool) -> Temporary { let window = self.window.root(); + window.init(); match self.GetDocumentElement().root() { None => { @@ -366,14 +370,9 @@ impl<'a> PrivateDocumentHelpers for JSRef<'a, Document> { } fn get_html_element(self) -> Option> { - match self.GetDocumentElement().root() { - Some(ref root) if { - let root: JSRef = NodeCast::from_ref(**root); - root.type_id() == ElementNodeTypeId(HTMLHtmlElementTypeId) - } => Some(Temporary::from_rooted(HTMLHtmlElementCast::to_ref(**root).unwrap())), - - _ => None, - } + self.GetDocumentElement().root().as_ref().and_then(|root| { + HTMLHtmlElementCast::to_ref(**root) + }).map(|elem| Temporary::from_rooted(elem)) } } @@ -383,7 +382,7 @@ impl<'a> DocumentMethods for JSRef<'a, Document> { if self.implementation.get().is_none() { self.implementation.assign(Some(DOMImplementation::new(self))); } - Temporary::new(self.implementation.get().as_ref().unwrap().clone()) + self.implementation.get().unwrap() } // http://dom.spec.whatwg.org/#dom-document-url diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index a4ae4734ffc6..3de6e7d0dc4a 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -12,7 +12,7 @@ use dom::bindings::codegen::Bindings::ElementBinding; use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods; use dom::bindings::codegen::Bindings::NamedNodeMapBinding::NamedNodeMapMethods; use dom::bindings::codegen::InheritTypes::{ElementDerived, NodeCast}; -use dom::bindings::js::{JS, JSRef, Temporary, TemporaryPushable}; +use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, TemporaryPushable}; use dom::bindings::js::{OptionalSettable, OptionalRootable, Root}; use dom::bindings::trace::Traceable; use dom::bindings::utils::{Reflectable, Reflector}; @@ -40,7 +40,8 @@ use servo_util::namespace::{Namespace, Null}; use servo_util::str::DOMString; use std::ascii::StrAsciiExt; -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; +use std::default::Default; use std::mem; #[jstraceable] @@ -52,8 +53,8 @@ pub struct Element { pub prefix: Option, pub attrs: RefCell>>, pub style_attribute: Traceable>>, - pub attr_list: Cell>>, - class_list: Cell>>, + pub attr_list: MutNullableJS, + class_list: MutNullableJS, } impl ElementDerived for EventTarget { @@ -157,8 +158,8 @@ impl Element { namespace: namespace, prefix: prefix, attrs: RefCell::new(vec!()), - attr_list: Cell::new(None), - class_list: Cell::new(None), + attr_list: Default::default(), + class_list: Default::default(), style_attribute: Traceable::new(RefCell::new(None)), } } @@ -323,9 +324,9 @@ pub trait AttributeHandlers { impl<'a> AttributeHandlers for JSRef<'a, Element> { fn get_attribute(self, namespace: Namespace, local_name: &str) -> Option> { let local_name = Atom::from_slice(local_name); - self.attrs.borrow().iter().map(|attr| attr.root()).find(|attr| { + self.attrs.borrow().iter().map(|attr| *attr.root()).find(|attr| { *attr.local_name() == local_name && attr.namespace == namespace - }).map(|x| Temporary::from_rooted(*x)) + }).map(|x| Temporary::from_rooted(x)) } fn set_attribute_from_parser(self, local_name: Atom, @@ -559,11 +560,11 @@ impl<'a> ElementMethods for JSRef<'a, Element> { // http://dom.spec.whatwg.org/#dom-element-classlist fn ClassList(self) -> Temporary { match self.class_list.get() { - Some(class_list) => Temporary::new(class_list), + Some(class_list) => class_list, None => { - let class_list = DOMTokenList::new(self, "class").root(); - self.class_list.assign(Some(class_list.deref().clone())); - Temporary::from_rooted(*class_list) + let class_list = DOMTokenList::new(self, "class"); + self.class_list.assign(Some(class_list)); + self.class_list.get().unwrap() } } } @@ -572,7 +573,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { fn Attributes(self) -> Temporary { match self.attr_list.get() { None => (), - Some(ref list) => return Temporary::new(list.clone()), + Some(list) => return list, } let doc = { @@ -582,7 +583,7 @@ impl<'a> ElementMethods for JSRef<'a, Element> { let window = doc.deref().window.root(); let list = NamedNodeMap::new(*window, self); self.attr_list.assign(Some(list)); - Temporary::new(self.attr_list.get().as_ref().unwrap().clone()) + self.attr_list.get().unwrap() } // http://dom.spec.whatwg.org/#dom-element-getattribute @@ -915,6 +916,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { match self.get_attribute(Null, "id").root() { Some(attr) => { + attr.init(); let doc = document_from_node(*self).root(); let value = attr.deref().Value(); if !value.is_empty() { @@ -936,6 +938,7 @@ impl<'a> VirtualMethods for JSRef<'a, Element> { match self.get_attribute(Null, "id").root() { Some(attr) => { + attr.init(); let doc = document_from_node(*self).root(); let value = attr.deref().Value(); if !value.is_empty() { diff --git a/components/script/dom/event.rs b/components/script/dom/event.rs index 69caf3f137c0..858ac31becd9 100644 --- a/components/script/dom/event.rs +++ b/components/script/dom/event.rs @@ -6,12 +6,13 @@ use dom::bindings::codegen::Bindings::EventBinding; use dom::bindings::codegen::Bindings::EventBinding::{EventConstants, EventMethods}; use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; -use dom::bindings::js::{JS, JSRef, Temporary}; +use dom::bindings::js::{MutNullableJS, JSRef, Temporary}; use dom::bindings::trace::Traceable; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::eventtarget::EventTarget; use servo_util::str::DOMString; use std::cell::{Cell, RefCell}; +use std::default::Default; use time; @@ -40,8 +41,8 @@ pub enum EventTypeId { pub struct Event { pub type_id: EventTypeId, reflector_: Reflector, - pub current_target: Cell>>, - pub target: Cell>>, + pub current_target: MutNullableJS, + pub target: MutNullableJS, type_: Traceable>, pub phase: Traceable>, pub canceled: Traceable>, @@ -60,8 +61,8 @@ impl Event { Event { type_id: type_id, reflector_: Reflector::new(), - current_target: Cell::new(None), - target: Cell::new(None), + current_target: Default::default(), + target: Default::default(), phase: Traceable::new(Cell::new(PhaseNone)), type_: Traceable::new(RefCell::new("".to_string())), canceled: Traceable::new(Cell::new(false)), @@ -108,11 +109,11 @@ impl<'a> EventMethods for JSRef<'a, Event> { } fn GetTarget(self) -> Option> { - self.target.get().as_ref().map(|target| Temporary::new(target.clone())) + self.target.get() } fn GetCurrentTarget(self) -> Option> { - self.current_target.get().as_ref().map(|target| Temporary::new(target.clone())) + self.current_target.get() } fn DefaultPrevented(self) -> bool { @@ -158,7 +159,7 @@ impl<'a> EventMethods for JSRef<'a, Event> { self.stop_immediate.deref().set(false); self.canceled.deref().set(false); self.trusted.deref().set(false); - self.target.set(None); + self.target.clear(); *self.type_.deref().borrow_mut() = type_; self.bubbles.deref().set(bubbles); self.cancelable.deref().set(cancelable); diff --git a/components/script/dom/eventdispatcher.rs b/components/script/dom/eventdispatcher.rs index 0fa26d607155..3cbb370e1bc8 100644 --- a/components/script/dom/eventdispatcher.rs +++ b/components/script/dom/eventdispatcher.rs @@ -5,7 +5,8 @@ use dom::bindings::callback::ReportExceptions; use dom::bindings::codegen::Bindings::EventBinding::EventMethods; use dom::bindings::codegen::InheritTypes::{EventTargetCast, NodeCast, NodeDerived}; -use dom::bindings::js::{JS, JSRef, OptionalSettable, OptionalRootable, Root}; +use dom::bindings::js::{JS, JSRef, OptionalSettable, OptionalRootable}; +use dom::bindings::trace::RootedVec; use dom::eventtarget::{Capturing, Bubbling, EventTarget}; use dom::event::{Event, PhaseAtTarget, PhaseNone, PhaseBubbling, PhaseCapturing}; use dom::node::{Node, NodeHelpers}; @@ -26,28 +27,29 @@ pub fn dispatch_event<'a, 'b>(target: JSRef<'a, EventTarget>, let type_ = event.Type(); //TODO: no chain if not participating in a tree - let mut chain: Vec> = if target.deref().is_node() { + let mut chain: RootedVec = RootedVec::new(); + chain.init(); + + if target.deref().is_node() { let target_node: JSRef = NodeCast::to_ref(target).unwrap(); - target_node.ancestors().map(|ancestor| { + for ancestor in target_node.ancestors() { let ancestor_target: JSRef = EventTargetCast::from_ref(ancestor); - JS::from_rooted(ancestor_target).root() - }).collect() - } else { - vec!() - }; + chain.push(JS::from_rooted(ancestor_target)); + } + } event.deref().phase.deref().set(PhaseCapturing); //FIXME: The "callback this value" should be currentTarget /* capturing */ - for cur_target in chain.as_slice().iter().rev() { + for cur_target in chain.as_slice().iter().rev().map(|node| node.root()) { let stopped = match cur_target.get_listeners_for(type_.as_slice(), Capturing) { Some(listeners) => { event.current_target.assign(Some(cur_target.deref().clone())); for listener in listeners.iter() { // Explicitly drop any exception on the floor. - let _ = listener.HandleEvent_(**cur_target, event, ReportExceptions); + let _ = listener.HandleEvent_(*cur_target, event, ReportExceptions); if event.deref().stop_immediate.deref().get() { break; @@ -86,13 +88,13 @@ pub fn dispatch_event<'a, 'b>(target: JSRef<'a, EventTarget>, if event.deref().bubbles.deref().get() && !event.deref().stop_propagation.deref().get() { event.deref().phase.deref().set(PhaseBubbling); - for cur_target in chain.iter() { + for cur_target in chain.as_slice().iter().map(|node| node.root()) { let stopped = match cur_target.deref().get_listeners_for(type_.as_slice(), Bubbling) { Some(listeners) => { event.deref().current_target.assign(Some(cur_target.deref().clone())); for listener in listeners.iter() { // Explicitly drop any exception on the floor. - let _ = listener.HandleEvent_(**cur_target, event, ReportExceptions); + let _ = listener.HandleEvent_(*cur_target, event, ReportExceptions); if event.deref().stop_immediate.deref().get() { break; @@ -125,15 +127,9 @@ pub fn dispatch_event<'a, 'b>(target: JSRef<'a, EventTarget>, None => {} } - // Root ordering restrictions mean we need to unroot the chain entries - // in the same order they were rooted. - while chain.len() > 0 { - let _ = chain.pop(); - } - event.dispatching.deref().set(false); event.phase.deref().set(PhaseNone); - event.current_target.set(None); + event.current_target.clear(); !event.DefaultPrevented() } diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs index 682379bfdce5..eb7b5b3b9482 100644 --- a/components/script/dom/eventtarget.rs +++ b/components/script/dom/eventtarget.rs @@ -9,21 +9,23 @@ use dom::bindings::codegen::Bindings::EventTargetBinding::EventTargetMethods; use dom::bindings::error::{Fallible, InvalidState, report_pending_exception}; use dom::bindings::js::JSRef; use dom::bindings::trace::Traceable; -use dom::bindings::utils::{Reflectable, Reflector}; +use dom::bindings::utils::{Reflectable, Reflector, object_handle}; use dom::event::Event; use dom::eventdispatcher::dispatch_event; use dom::node::NodeTypeId; use dom::workerglobalscope::WorkerGlobalScopeId; use dom::xmlhttprequest::XMLHttpRequestId; use dom::virtualmethods::VirtualMethods; -use js::jsapi::{JS_CompileUCFunction, JS_GetFunctionObject, JS_CloneFunctionObject}; -use js::jsapi::{JSContext, JSObject}; use servo_util::str::DOMString; -use libc::{c_char, size_t}; -use std::cell::RefCell; -use std::ptr; + +use js::glue::CompileEventHandler; +use js::jsapi::{JS_GetFunctionObject, JS_CloneFunctionObject}; +use js::jsapi::{JSContext, JSObject}; +use js::rust::{JSAutoRequest, JSAutoCompartment}; use url::Url; +use libc::{c_char, size_t}; +use std::cell::RefCell; use std::collections::hashmap::HashMap; #[deriving(PartialEq)] @@ -187,24 +189,28 @@ impl<'a> EventTargetHelpers for JSRef<'a, EventTarget> { static arg_names: [*const c_char, ..1] = [&arg_name as *const c_char]; let source: Vec = source.as_slice().utf16_units().collect(); + + let _ar = JSAutoRequest::new(cx); + let _ac = JSAutoCompartment::new(cx, scope); let handler = unsafe { - JS_CompileUCFunction(cx, - ptr::null_mut(), - name.as_ptr(), - nargs, - &arg_names as *const *const i8 as *mut *const i8, - source.as_ptr(), - source.len() as size_t, - url.as_ptr(), - lineno) + CompileEventHandler(cx, + name.as_ptr(), + nargs, + arg_names.as_ptr(), + source.as_ptr(), + source.len() as size_t, + url.as_ptr(), + lineno) }; if handler.is_null() { report_pending_exception(cx, self.reflector().get_jsobject()); return; } + let handler = unsafe { JS_GetFunctionObject(handler) }; + assert!(handler.is_not_null()); let funobj = unsafe { - JS_CloneFunctionObject(cx, JS_GetFunctionObject(handler), scope) + JS_CloneFunctionObject(cx, object_handle(&handler), object_handle(&scope)) }; assert!(funobj.is_not_null()); self.set_event_handler_common(ty, Some(EventHandlerNonNull::new(funobj))); diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 7ffe03eff811..4f37362634ed 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -92,7 +92,7 @@ pub trait LayoutHTMLImageElementHelpers { impl LayoutHTMLImageElementHelpers for JS { unsafe fn image(&self) -> Option { - (*self.unsafe_get()).image.borrow().clone() + (*self.unsafe_get()).image.deref().borrow().clone() } } diff --git a/components/script/dom/mouseevent.rs b/components/script/dom/mouseevent.rs index 9efc5a97d3ec..2332417da189 100644 --- a/components/script/dom/mouseevent.rs +++ b/components/script/dom/mouseevent.rs @@ -9,7 +9,7 @@ use dom::bindings::codegen::InheritTypes::{UIEventCast, MouseEventDerived}; use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::global; -use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, OptionalSettable}; +use dom::bindings::js::{MutNullableJS, JSRef, RootedReference, Temporary, OptionalSettable}; use dom::bindings::trace::Traceable; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::event::{Event, MouseEventTypeId}; @@ -18,6 +18,7 @@ use dom::uievent::UIEvent; use dom::window::Window; use servo_util::str::DOMString; use std::cell::Cell; +use std::default::Default; #[jstraceable] #[must_root] @@ -32,7 +33,7 @@ pub struct MouseEvent { pub alt_key: Traceable>, pub meta_key: Traceable>, pub button: Traceable>, - pub related_target: Cell>> + pub related_target: MutNullableJS } impl MouseEventDerived for Event { @@ -54,7 +55,7 @@ impl MouseEvent { alt_key: Traceable::new(Cell::new(false)), meta_key: Traceable::new(Cell::new(false)), button: Traceable::new(Cell::new(0)), - related_target: Cell::new(None) + related_target: Default::default(), } } @@ -142,7 +143,7 @@ impl<'a> MouseEventMethods for JSRef<'a, MouseEvent> { } fn GetRelatedTarget(self) -> Option> { - self.related_target.get().clone().map(|target| Temporary::new(target)) + self.related_target.get() } fn InitMouseEvent(self, diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs index b62225314e23..f716455fcd2c 100644 --- a/components/script/dom/node.rs +++ b/components/script/dom/node.rs @@ -22,9 +22,9 @@ use dom::bindings::codegen::InheritTypes::HTMLOptGroupElementDerived; use dom::bindings::error::{Fallible, NotFound, HierarchyRequest, Syntax}; use dom::bindings::global::GlobalRef; use dom::bindings::global; -use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, Root, OptionalUnrootable}; +use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, Root}; use dom::bindings::js::{OptionalSettable, TemporaryPushable, OptionalRootedRootable}; -use dom::bindings::js::{ResultRootable, OptionalRootable}; +use dom::bindings::js::{ResultRootable, OptionalRootable, MutNullableJS}; use dom::bindings::trace::{Traceable, Untraceable}; use dom::bindings::utils; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; @@ -57,7 +57,8 @@ use js::jsapi::{JSContext, JSObject, JSRuntime}; use js::jsfriendapi; use libc; use libc::uintptr_t; -use std::cell::{Cell, RefCell, Ref, RefMut}; +use std::cell::{RefCell, Ref, RefMut}; +use std::default::Default; use std::iter::{Map, Filter}; use std::mem; use style; @@ -80,25 +81,25 @@ pub struct Node { type_id: NodeTypeId, /// The parent of this node. - parent_node: Cell>>, + parent_node: MutNullableJS, /// The first child of this node. - first_child: Cell>>, + first_child: MutNullableJS, /// The last child of this node. - last_child: Cell>>, + last_child: MutNullableJS, /// The next sibling of this node. - next_sibling: Cell>>, + next_sibling: MutNullableJS, /// The previous sibling of this node. - prev_sibling: Cell>>, + prev_sibling: MutNullableJS, /// The document that this node belongs to. - owner_doc: Cell>>, + owner_doc: MutNullableJS, /// The live list of children return by .childNodes. - child_list: Cell>>, + child_list: MutNullableJS, /// A bitfield of flags for node items. flags: Traceable>, @@ -358,9 +359,9 @@ impl<'a> PrivateNodeHelpers for JSRef<'a, Node> { } } - child.prev_sibling.set(None); - child.next_sibling.set(None); - child.parent_node.set(None); + child.prev_sibling.clear(); + child.next_sibling.clear(); + child.parent_node.clear(); } } @@ -461,25 +462,25 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> { } fn parent_node(&self) -> Option> { - self.deref().parent_node.get().map(|node| Temporary::new(node)) + self.deref().parent_node.get() } fn first_child(&self) -> Option> { - self.deref().first_child.get().map(|node| Temporary::new(node)) + self.deref().first_child.get() } fn last_child(&self) -> Option> { - self.deref().last_child.get().map(|node| Temporary::new(node)) + self.deref().last_child.get() } /// Returns the previous sibling of this node. Fails if this node is borrowed mutably. fn prev_sibling(&self) -> Option> { - self.deref().prev_sibling.get().map(|node| Temporary::new(node)) + self.deref().prev_sibling.get() } /// Returns the next sibling of this node. Fails if this node is borrowed mutably. fn next_sibling(&self) -> Option> { - self.deref().next_sibling.get().map(|node| Temporary::new(node)) + self.deref().next_sibling.get() } #[inline] @@ -578,7 +579,7 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> { fn is_parent_of(&self, child: JSRef) -> bool { match child.parent_node() { - Some(parent) if parent == Temporary::from_rooted(*self) => true, + Some(ref parent) if parent == &Temporary::from_rooted(*self) => true, _ => false } } @@ -651,7 +652,7 @@ impl<'m, 'n> NodeHelpers<'m, 'n> for JSRef<'n, Node> { } fn owner_doc(&self) -> Temporary { - Temporary::new(self.owner_doc.get().as_ref().unwrap().clone()) + self.owner_doc.get().unwrap() } fn set_owner_doc(&self, document: JSRef) { @@ -777,32 +778,32 @@ impl LayoutNodeHelpers for JS { #[inline] unsafe fn parent_node_ref(&self) -> Option> { - (*self.unsafe_get()).parent_node.get() + (*self.unsafe_get()).parent_node.get_inner() } #[inline] unsafe fn first_child_ref(&self) -> Option> { - (*self.unsafe_get()).first_child.get() + (*self.unsafe_get()).first_child.get_inner() } #[inline] unsafe fn last_child_ref(&self) -> Option> { - (*self.unsafe_get()).last_child.get() + (*self.unsafe_get()).last_child.get_inner() } #[inline] unsafe fn prev_sibling_ref(&self) -> Option> { - (*self.unsafe_get()).prev_sibling.get() + (*self.unsafe_get()).prev_sibling.get_inner() } #[inline] unsafe fn next_sibling_ref(&self) -> Option> { - (*self.unsafe_get()).next_sibling.get() + (*self.unsafe_get()).next_sibling.get_inner() } #[inline] unsafe fn owner_doc_for_layout(&self) -> JS { - (*self.unsafe_get()).owner_doc.get().unwrap() + (*self.unsafe_get()).owner_doc.get_inner().unwrap() } } @@ -1025,13 +1026,13 @@ impl Node { eventtarget: EventTarget::new_inherited(NodeTargetTypeId(type_id)), type_id: type_id, - parent_node: Cell::new(None), - first_child: Cell::new(None), - last_child: Cell::new(None), - next_sibling: Cell::new(None), - prev_sibling: Cell::new(None), - owner_doc: Cell::new(doc.unrooted()), - child_list: Cell::new(None), + parent_node: Default::default(), + first_child: Default::default(), + last_child: Default::default(), + next_sibling: Default::default(), + prev_sibling: Default::default(), + owner_doc: MutNullableJS::new(doc), + child_list: Default::default(), flags: Traceable::new(RefCell::new(NodeFlags::new(type_id))), @@ -1304,7 +1305,7 @@ impl Node { fn pre_remove(child: JSRef, parent: JSRef) -> Fallible> { // Step 1. match child.parent_node() { - Some(node) if node != Temporary::from_rooted(parent) => return Err(NotFound), + Some(ref node) if node != &Temporary::from_rooted(parent) => return Err(NotFound), _ => () } @@ -1342,6 +1343,7 @@ impl Node { Some(doc) => JS::from_rooted(doc).root(), None => node.owner_doc().root() }; + document.init(); // Step 2. // XXXabinader: clone() for each node as trait? @@ -1396,6 +1398,7 @@ impl Node { NodeCast::from_temporary(pi) }, }.root(); + copy.init(); // Step 3. let document = if copy.is_document() { @@ -1404,6 +1407,7 @@ impl Node { } else { JS::from_rooted(*document).root() }; + document.init(); assert!(&*copy.owner_doc().root() == &*document); // Step 4 (some data already copied in step 2). @@ -1420,6 +1424,7 @@ impl Node { // FIXME: https://github.com/mozilla/servo/issues/1737 let window = document.deref().window.root(); + window.init(); for attr in node_elem.deref().attrs.borrow().iter().map(|attr| attr.root()) { copy_elem.deref().attrs.borrow_mut().push_unrooted( &Attr::new(*window, @@ -1535,7 +1540,7 @@ impl<'a> NodeMethods for JSRef<'a, Node> { // http://dom.spec.whatwg.org/#dom-node-parentnode fn GetParentNode(self) -> Option> { - self.parent_node.get().map(|node| Temporary::new(node)) + self.parent_node.get() } // http://dom.spec.whatwg.org/#dom-node-parentelement @@ -1558,34 +1563,34 @@ impl<'a> NodeMethods for JSRef<'a, Node> { fn ChildNodes(self) -> Temporary { match self.child_list.get() { None => (), - Some(ref list) => return Temporary::new(list.clone()), + Some(list) => return list, } let doc = self.owner_doc().root(); let window = doc.deref().window.root(); let child_list = NodeList::new_child_list(*window, self); self.child_list.assign(Some(child_list)); - Temporary::new(self.child_list.get().as_ref().unwrap().clone()) + self.child_list.get().unwrap() } // http://dom.spec.whatwg.org/#dom-node-firstchild fn GetFirstChild(self) -> Option> { - self.first_child.get().map(|node| Temporary::new(node)) + self.first_child.get() } // http://dom.spec.whatwg.org/#dom-node-lastchild fn GetLastChild(self) -> Option> { - self.last_child.get().map(|node| Temporary::new(node)) + self.last_child.get() } // http://dom.spec.whatwg.org/#dom-node-previoussibling fn GetPreviousSibling(self) -> Option> { - self.prev_sibling.get().map(|node| Temporary::new(node)) + self.prev_sibling.get() } // http://dom.spec.whatwg.org/#dom-node-nextsibling fn GetNextSibling(self) -> Option> { - self.next_sibling.get().map(|node| Temporary::new(node)) + self.next_sibling.get() } // http://dom.spec.whatwg.org/#dom-node-nodevalue diff --git a/components/script/dom/treewalker.rs b/components/script/dom/treewalker.rs index ba667c222e86..c4401da330bb 100644 --- a/components/script/dom/treewalker.rs +++ b/components/script/dom/treewalker.rs @@ -266,9 +266,9 @@ impl<'a, 'b> PrivateTreeWalkerHelpers<'a, 'b> for JSRef<'a, TreeWalker> { // "5. If result is FILTER_REJECT or sibling is null, // then set sibling to node's next sibling if type is next, // and node's previous sibling if type is previous." - match (result, sibling_op) { + match (result, &sibling_op) { (Ok(NodeFilterConstants::FILTER_REJECT), _) - | (_, None) => sibling_op = next_sibling(node), + | (_, &None) => sibling_op = next_sibling(node), _ => {} } } diff --git a/components/script/dom/uievent.rs b/components/script/dom/uievent.rs index eac29a4ab249..86501d47324c 100644 --- a/components/script/dom/uievent.rs +++ b/components/script/dom/uievent.rs @@ -9,7 +9,7 @@ use dom::bindings::codegen::InheritTypes::{EventCast, UIEventDerived}; use dom::bindings::error::Fallible; use dom::bindings::global::GlobalRef; use dom::bindings::global; -use dom::bindings::js::{JS, JSRef, RootedReference, Temporary, OptionalSettable}; +use dom::bindings::js::{MutNullableJS, JSRef, RootedReference, Temporary, OptionalSettable}; use dom::bindings::trace::Traceable; use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; use dom::event::{Event, EventTypeId, UIEventTypeId}; @@ -17,12 +17,13 @@ use dom::window::Window; use servo_util::str::DOMString; use std::cell::Cell; +use std::default::Default; #[jstraceable] #[must_root] pub struct UIEvent { pub event: Event, - view: Cell>>, + view: MutNullableJS, detail: Traceable> } @@ -36,7 +37,7 @@ impl UIEvent { pub fn new_inherited(type_id: EventTypeId) -> UIEvent { UIEvent { event: Event::new_inherited(type_id), - view: Cell::new(None), + view: Default::default(), detail: Traceable::new(Cell::new(0)), } } @@ -70,7 +71,7 @@ impl UIEvent { impl<'a> UIEventMethods for JSRef<'a, UIEvent> { fn GetView(self) -> Option> { - self.view.get().map(|view| Temporary::new(view)) + self.view.get() } fn Detail(self) -> i32 { diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index d0c33ebc1cac..7e16c5b9dbb5 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -8,9 +8,10 @@ use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use dom::bindings::codegen::InheritTypes::EventTargetCast; use dom::bindings::error::{Fallible, InvalidCharacter}; use dom::bindings::global; -use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable}; +use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, OptionalSettable}; use dom::bindings::trace::{Traceable, Untraceable}; use dom::bindings::utils::{Reflectable, Reflector}; +use dom::bindings::utils::{object_handle, value_handle, mut_value_handle}; use dom::browsercontext::BrowserContext; use dom::console::Console; use dom::document::Document; @@ -29,7 +30,8 @@ use servo_net::image_cache_task::ImageCacheTask; use servo_util::str::{DOMString,HTML_SPACE_CHARACTERS}; use servo_util::task::{spawn_named}; -use js::jsapi::{JS_CallFunctionValue, JS_EvaluateUCScript}; +use js::glue::CallFunctionValue; +use js::jsapi::JS_EvaluateUCScript; use js::jsapi::JSContext; use js::jsapi::{JS_GC, JS_GetRuntime}; use js::jsval::JSVal; @@ -44,6 +46,7 @@ use std::cell::{Cell, RefCell}; use std::cmp; use std::comm::{channel, Sender}; use std::comm::Select; +use std::default::Default; use std::hash::{Hash, sip}; use std::io::timer::Timer; use std::ptr; @@ -81,16 +84,16 @@ pub struct Window { eventtarget: EventTarget, pub script_chan: ScriptChan, pub control_chan: ScriptControlChan, - console: Cell>>, - location: Cell>>, - navigator: Cell>>, + console: MutNullableJS, + location: MutNullableJS, + navigator: MutNullableJS, pub image_cache_task: ImageCacheTask, pub active_timers: Traceable>>, next_timer_handle: Traceable>, pub compositor: Untraceable>, pub browser_context: Traceable>>, pub page: Rc, - performance: Cell>>, + performance: MutNullableJS, pub navigationStart: u64, pub navigationStartPrecise: f64, screen: Cell>>, @@ -225,7 +228,7 @@ impl<'a> WindowMethods for JSRef<'a, Window> { let location = Location::new(self, page); self.location.assign(Some(location)); } - Temporary::new(self.location.get().as_ref().unwrap().clone()) + self.location.get().unwrap() } fn Console(self) -> Temporary { @@ -233,7 +236,7 @@ impl<'a> WindowMethods for JSRef<'a, Window> { let console = Console::new(&global::Window(self)); self.console.assign(Some(console)); } - Temporary::new(self.console.get().as_ref().unwrap().clone()) + self.console.get().unwrap() } fn Navigator(self) -> Temporary { @@ -241,7 +244,7 @@ impl<'a> WindowMethods for JSRef<'a, Window> { let navigator = Navigator::new(self); self.navigator.assign(Some(navigator)); } - Temporary::new(self.navigator.get().as_ref().unwrap().clone()) + self.navigator.get().unwrap() } fn SetTimeout(self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 { @@ -289,7 +292,7 @@ impl<'a> WindowMethods for JSRef<'a, Window> { let performance = Performance::new(self); self.performance.assign(Some(performance)); } - Temporary::new(self.performance.get().as_ref().unwrap().clone()) + self.performance.get().unwrap() } fn GetOnclick(self) -> Option { @@ -389,9 +392,9 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { with_compartment(cx, global, || { unsafe { - if JS_EvaluateUCScript(cx, global, code.as_ptr(), - code.len() as libc::c_uint, - filename.as_ptr(), 1, &mut rval) == 0 { + if !JS_EvaluateUCScript(cx, object_handle(&global), code.as_ptr(), + code.len() as libc::c_uint, + filename.as_ptr(), 1, mut_value_handle(&mut rval)) { debug!("error evaluating JS string"); } rval @@ -445,8 +448,9 @@ impl<'a> WindowHelpers for JSRef<'a, Window> { with_compartment(cx, this_value, || { let mut rval = NullValue(); unsafe { - JS_CallFunctionValue(cx, this_value, *data.funval, - 0, ptr::null_mut(), &mut rval); + CallFunctionValue(cx, object_handle(&this_value), + value_handle(&*data.funval), + 0, ptr::null(), mut_value_handle(&mut rval)); } }); @@ -529,16 +533,16 @@ impl Window { eventtarget: EventTarget::new_inherited(WindowTypeId), script_chan: script_chan, control_chan: control_chan, - console: Cell::new(None), + console: Default::default(), compositor: Untraceable::new(compositor), page: page, - location: Cell::new(None), - navigator: Cell::new(None), + location: Default::default(), + navigator: Default::default(), image_cache_task: image_cache_task, active_timers: Traceable::new(RefCell::new(HashMap::new())), next_timer_handle: Traceable::new(Cell::new(0)), browser_context: Traceable::new(RefCell::new(None)), - performance: Cell::new(None), + performance: Default::default(), navigationStart: time::get_time().sec as u64, navigationStartPrecise: time::precise_time_s(), screen: Cell::new(None), diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index 04bac9e2c9a5..c4d671dbd386 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -9,7 +9,8 @@ use dom::bindings::codegen::InheritTypes::EventTargetCast; use dom::bindings::error::{Fallible, Syntax}; use dom::bindings::global::{GlobalRef, GlobalField}; use dom::bindings::js::{JS, JSRef, Temporary}; -use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; +use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object, mut_value_handle}; +use dom::bindings::utils::value_handle; use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScope; use dom::eventtarget::{EventTarget, EventTargetHelpers, WorkerTypeId}; use dom::messageevent::MessageEvent; @@ -18,8 +19,8 @@ use script_task::{ScriptChan, DOMMessage}; use servo_util::str::DOMString; use js::glue::JS_STRUCTURED_CLONE_VERSION; -use js::jsapi::{JSContext, JS_AddObjectRoot, JS_RemoveObjectRoot}; -use js::jsapi::{JS_ReadStructuredClone, JS_WriteStructuredClone}; +use js::jsapi::{JSContext/*, JS_AddObjectRoot, JS_RemoveObjectRoot*/}; +use js::jsfriendapi::{JS_ReadStructuredClone, JS_WriteStructuredClone}; use js::jsval::{JSVal, UndefinedValue}; use url::UrlParser; @@ -88,8 +89,8 @@ impl Worker { unsafe { assert!(JS_ReadStructuredClone( global.root_ref().get_cx(), data as *const u64, nbytes, - JS_STRUCTURED_CLONE_VERSION, &mut message, - ptr::null(), ptr::null_mut()) != 0); + JS_STRUCTURED_CLONE_VERSION, mut_value_handle(&mut message), + ptr::null(), ptr::null_mut())); } let target: JSRef = EventTargetCast::from_ref(*worker); @@ -102,9 +103,9 @@ impl Worker { pub fn addref(&self) -> TrustedWorkerAddress { let refcount = self.refcount.get(); if refcount == 0 { - let cx = self.global.root().root_ref().get_cx(); + let _cx = self.global.root().root_ref().get_cx(); unsafe { - JS_AddObjectRoot(cx, self.reflector().rootable()); + //JS_AddObjectRoot(cx, self.reflector().rootable()); //XXXjdm } } self.refcount.set(refcount + 1); @@ -116,9 +117,9 @@ impl Worker { assert!(refcount > 0) self.refcount.set(refcount - 1); if refcount == 1 { - let cx = self.global.root().root_ref().get_cx(); + let _cx = self.global.root().root_ref().get_cx(); unsafe { - JS_RemoveObjectRoot(cx, self.reflector().rootable()); + //JS_RemoveObjectRoot(cx, self.reflector().rootable()); //XXXjdm } } } @@ -133,9 +134,11 @@ impl<'a> WorkerMethods for JSRef<'a, Worker> { fn PostMessage(self, cx: *mut JSContext, message: JSVal) { let mut data = ptr::null_mut(); let mut nbytes = 0; + let transferable = UndefinedValue(); unsafe { - assert!(JS_WriteStructuredClone(cx, message, &mut data, &mut nbytes, - ptr::null(), ptr::null_mut()) != 0); + assert!(JS_WriteStructuredClone(cx, value_handle(&message), &mut data, &mut nbytes, + ptr::null(), ptr::null_mut(), + value_handle(&transferable))); } self.addref(); diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 7bb38cf49df3..18a331246bd2 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -13,10 +13,10 @@ use dom::bindings::conversions::ToJSValConvertible; use dom::bindings::error::{Error, ErrorResult, Fallible, InvalidState, InvalidAccess}; use dom::bindings::error::{Network, Syntax, Security, Abort, Timeout}; use dom::bindings::global::{GlobalField, GlobalRef, WorkerField}; -use dom::bindings::js::{JS, JSRef, Temporary, OptionalRootedRootable}; +use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary, OptionalRootedRootable}; use dom::bindings::str::ByteString; use dom::bindings::trace::{Traceable, Untraceable}; -use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object}; +use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object, mut_value_handle}; use dom::document::Document; use dom::event::Event; use dom::eventtarget::{EventTarget, EventTargetHelpers, XMLHttpRequestTargetTypeId}; @@ -37,8 +37,7 @@ use http::headers::request::Header; use http::method::{Method, Get, Head, Connect, Trace, ExtensionMethod}; use http::status::Status; -use js::jsapi::{JS_AddObjectRoot, JS_ParseJSON, JS_RemoveObjectRoot, JSContext}; -use js::jsapi::JS_ClearPendingException; +use js::jsapi::{JS_ParseJSON, JS_ClearPendingException, JSContext}; use js::jsval::{JSVal, NullValue, UndefinedValue}; use libc; @@ -53,6 +52,7 @@ use servo_util::task::spawn_named; use std::ascii::StrAsciiExt; use std::cell::{Cell, RefCell}; use std::comm::{Sender, Receiver, channel}; +use std::default::Default; use std::io::{BufReader, MemWriter, Timer}; use std::from_str::FromStr; use std::path::BytesContainer; @@ -115,7 +115,7 @@ pub struct XMLHttpRequest { status_text: Traceable>, response: Traceable>, response_type: Traceable>, - response_xml: Cell>>, + response_xml: MutNullableJS, response_headers: Untraceable>, // Associated concepts @@ -149,7 +149,7 @@ impl XMLHttpRequest { status_text: Traceable::new(RefCell::new(ByteString::new(vec!()))), response: Traceable::new(RefCell::new(ByteString::new(vec!()))), response_type: Traceable::new(Cell::new(_empty)), - response_xml: Cell::new(None), + response_xml: Default::default(), response_headers: Untraceable::new(RefCell::new(ResponseHeaderCollection::new())), request_method: Untraceable::new(RefCell::new(Get)), @@ -642,7 +642,7 @@ impl<'a> XMLHttpRequestMethods for JSRef<'a, XMLHttpRequest> { let decoded: Vec = decoded.as_slice().utf16_units().collect(); let mut vp = UndefinedValue(); unsafe { - if JS_ParseJSON(cx, decoded.as_ptr(), decoded.len() as u32, &mut vp) == 0 { + if !JS_ParseJSON(cx, decoded.as_ptr(), decoded.len() as u32, mut_value_handle(&mut vp)) { JS_ClearPendingException(cx); return NullValue(); } @@ -667,7 +667,7 @@ impl<'a> XMLHttpRequestMethods for JSRef<'a, XMLHttpRequest> { } } fn GetResponseXML(self) -> Option> { - self.response_xml.get().map(|response| Temporary::new(response)) + self.response_xml.get() } } @@ -716,7 +716,7 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> { // Creates a trusted address to the object, and roots it. Always pair this with a release() unsafe fn to_trusted(self) -> TrustedXHRAddress { if self.pinned_count.deref().get() == 0 { - JS_AddObjectRoot(self.global.root().root_ref().get_cx(), self.reflector().rootable()); + //XXX JS_AddObjectRoot(self.global.root().root_ref().get_cx(), self.reflector().rootable()); } let pinned_count = self.pinned_count.deref().get(); self.pinned_count.deref().set(pinned_count + 1); @@ -735,7 +735,7 @@ impl<'a> PrivateXMLHttpRequestHelpers for JSRef<'a, XMLHttpRequest> { self.pinned_count.deref().set(pinned_count - 1); if self.pinned_count.deref().get() == 0 { unsafe { - JS_RemoveObjectRoot(self.global.root().root_ref().get_cx(), self.reflector().rootable()); + //XXX JS_RemoveObjectRoot(self.global.root().root_ref().get_cx(), self.reflector().rootable()); } } } diff --git a/components/script/html/hubbub_html_parser.rs b/components/script/html/hubbub_html_parser.rs index 097f8438cb5a..f598630a5387 100644 --- a/components/script/html/hubbub_html_parser.rs +++ b/components/script/html/hubbub_html_parser.rs @@ -411,7 +411,9 @@ pub fn parse_html(page: &Page, unsafe { debug!("append child {:x} {:x}", parent, child); let child: Root = from_hubbub_node(child).root(); + child.init(); let parent: Root = from_hubbub_node(parent).root(); + parent.init(); assert!(parent.deref().AppendChild(*child).is_ok()); } child diff --git a/components/script/lib.rs b/components/script/lib.rs index 695aef3c1b57..23947fa74a3c 100644 --- a/components/script/lib.rs +++ b/components/script/lib.rs @@ -214,3 +214,16 @@ pub mod html { pub mod layout_interface; pub mod page; pub mod script_task; + +pub fn init() { + unsafe { + js::jsapi::JS_Init(); + } +} + +pub fn shutdown() { + // Not strictly necessary, and hard to synchronize with native script tasks + /*unsafe { + js::jsapi::JS_ShutDown(); + }*/ +} diff --git a/components/script/page.rs b/components/script/page.rs index da2b99c0c6ff..20633bba106b 100644 --- a/components/script/page.rs +++ b/components/script/page.rs @@ -5,7 +5,7 @@ use dom::attr::AttrHelpers; use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods; use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast}; -use dom::bindings::js::{JS, JSRef, Temporary}; +use dom::bindings::js::{MutNullableJS, JS, JSRef, Temporary}; use dom::bindings::js::OptionalRootable; use dom::bindings::trace::{Traceable, Untraceable}; use dom::bindings::utils::GlobalStaticData; @@ -31,6 +31,7 @@ use servo_util::namespace::Null; use servo_util::str::DOMString; use std::cell::{Cell, RefCell, Ref, RefMut}; use std::comm::{channel, Receiver, Empty, Disconnected}; +use std::default::Default; use std::mem::replace; use std::rc::Rc; use url::Url; @@ -79,7 +80,7 @@ pub struct Page { pub resize_event: Untraceable>>, /// Pending scroll to fragment event, if any - pub fragment_node: Cell>>, + pub fragment_node: MutNullableJS, /// Associated resource task for use by DOM objects like XMLHttpRequest pub resource_task: Untraceable, @@ -153,7 +154,7 @@ impl Page { url: Untraceable::new(RefCell::new(None)), next_subpage_id: Traceable::new(Cell::new(SubpageId(0))), resize_event: Untraceable::new(Cell::new(None)), - fragment_node: Cell::new(None), + fragment_node: Default::default(), last_reflow_id: Traceable::new(Cell::new(0)), resource_task: Untraceable::new(resource_task), constellation_chan: Untraceable::new(constellation_chan), diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 88c84ef5b741..72284632ae10 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -14,9 +14,8 @@ use dom::bindings::conversions::{FromJSValConvertible, Empty}; use dom::bindings::global; use dom::bindings::js::{JS, JSRef, RootCollection, Temporary, OptionalSettable}; use dom::bindings::js::OptionalRootable; -use dom::bindings::trace::JSTraceable; +use dom::bindings::trace::{JSTraceable, RootedCollections, trace_collections}; use dom::bindings::utils::Reflectable; -use dom::bindings::utils::{wrap_for_same_compartment, pre_wrap}; use dom::document::{Document, HTMLDocument, DocumentHelpers}; use dom::element::{Element, HTMLButtonElementTypeId, HTMLInputElementTypeId}; use dom::element::{HTMLSelectElementTypeId, HTMLTextAreaElementTypeId, HTMLOptionElementTypeId}; @@ -56,10 +55,11 @@ use servo_util::geometry::to_frac_px; use servo_util::task::spawn_named_with_send_on_failure; use geom::point::Point2D; -use js::jsapi::{JS_SetWrapObjectCallbacks, JS_SetGCZeal, JS_DEFAULT_ZEAL_FREQ, JS_GC}; -use js::jsapi::{JSContext, JSRuntime, JSTracer}; +use js::JS_DEFAULT_ZEAL_FREQ; +use js::jsapi::{/*JS_SetWrapObjectCallbacks,*/ JS_SetGCZeal, JS_GC}; +use js::jsapi::{JSContext, JSRuntime, JSTracer, JS_AddExtraGCRootsTracer}; use js::jsapi::{JS_SetGCParameter, JSGC_MAX_BYTES}; -use js::rust::{Cx, RtUtils}; +use js::rust::{Cx, RtUtils, JSAutoRequest}; use js::rust::with_compartment; use js; use url::Url; @@ -67,6 +67,7 @@ use url::Url; use libc::size_t; use std::any::{Any, AnyRefExt}; use std::cell::RefCell; +use std::collections::HashSet; use std::comm::{channel, Sender, Receiver, Select}; use std::mem::replace; use std::rc::Rc; @@ -273,7 +274,7 @@ impl ScriptTaskFactory for ScriptTask { // This must always be the very last operation performed before the task completes failsafe.neuter(); - }, FailureMsg(failure_msg), const_chan, false); + }, FailureMsg(failure_msg), const_chan, true); } } @@ -292,8 +293,9 @@ impl ScriptTask { devtools_chan: Option, window_size: WindowSizeData) -> Rc { + RootedCollections.replace(Some(RefCell::new(HashSet::new()))); let (js_runtime, js_context) = ScriptTask::new_rt_and_cx(); - unsafe { + /*unsafe { // JS_SetWrapObjectCallbacks clobbers the existing wrap callback, // and JSCompartment::wrap crashes if that happens. The only way // to retrieve the default callback is as the result of @@ -306,7 +308,7 @@ impl ScriptTask { callback, Some(wrap_for_same_compartment), Some(pre_wrap)); - } + }*/ let page = Page::new(id, None, layout_chan, window_size, resource_task.clone(), @@ -347,6 +349,10 @@ impl ScriptTask { let ptr: *mut JSRuntime = (*js_runtime).ptr; ptr.is_not_null() }); + unsafe { + JS_AddExtraGCRootsTracer((*js_runtime).ptr, Some(trace_collections), + RootedCollections.get().get_ref().deref() as *const _ as *mut _); + } // Unconstrain the runtime's threshold on nominal heap size, to avoid // triggering GC too often if operating continuously near an arbitrary @@ -365,7 +371,7 @@ impl ScriptTask { js_context.set_default_options_and_version(); js_context.set_logging_error_reporter(); unsafe { - JS_SetGCZeal((*js_context).ptr, 0, JS_DEFAULT_ZEAL_FREQ); + JS_SetGCZeal((*js_context).ptr, 0, js::JS_DEFAULT_ZEAL_FREQ); } (js_runtime, js_context) @@ -385,7 +391,10 @@ impl ScriptTask { /// Handle incoming control messages. fn handle_msgs(&self) -> bool { - let roots = RootCollection::new(); + let cx = self.js_context.borrow().get_ref().deref().ptr; + let mut _ar = Some(JSAutoRequest::new(cx)); + + let roots = RootCollection::new(self.get_cx()); let _stack_roots_tls = StackRootTLS::new(&roots); // Handle pending resize events. @@ -493,8 +502,14 @@ impl ScriptTask { FromScript(NavigateMsg(direction)) => self.handle_navigate_msg(direction), FromConstellation(ReflowCompleteMsg(id, reflow_id)) => self.handle_reflow_complete_msg(id, reflow_id), FromConstellation(ResizeInactiveMsg(id, new_size)) => self.handle_resize_inactive_msg(id, new_size), - FromConstellation(ExitPipelineMsg(id)) => if self.handle_exit_pipeline_msg(id) { return false }, - FromScript(ExitWindowMsg(id)) => self.handle_exit_window_msg(id), + FromConstellation(ExitPipelineMsg(id)) => { + _ar = None; + if self.handle_exit_pipeline_msg(id) { return false } + } + FromScript(ExitWindowMsg(id)) => { + _ar = None; + self.handle_exit_window_msg(id) + } FromConstellation(ResizeMsg(..)) => fail!("should have handled ResizeMsg already"), FromScript(XHRProgressMsg(addr, progress)) => XMLHttpRequest::handle_xhr_progress(addr, progress), FromScript(DOMMessage(..)) => fail!("unexpected message"), @@ -725,6 +740,9 @@ impl ScriptTask { let cx = self.js_context.borrow(); let cx = cx.as_ref().unwrap(); + + let _ar = JSAutoRequest::new(cx.deref().ptr); + // Create the window and document objects. let window = Window::new(cx.deref().ptr, page.clone(), @@ -877,8 +895,9 @@ impl ScriptTask { page.reflow(ReflowForDisplay, self.control_chan.clone(), &*self.compositor) } - let mut fragment_node = page.fragment_node.get(); - match fragment_node.take().map(|node| node.root()) { + let fragment_node = page.fragment_node.get(); + page.fragment_node.clear(); + match fragment_node.map(|node| node.root()) { Some(node) => self.scroll_fragment_point(pipeline_id, *node), None => {} } diff --git a/components/util/lib.rs b/components/util/lib.rs index 89fcec41d933..da9c953f57d6 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -6,7 +6,7 @@ #![deny(unused_imports, unused_variable)] -#![feature(phase)] +#![feature(phase, unsafe_destructor)] #[phase(plugin, link)] extern crate log; diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 05ea9503ff38..4704ba6f0f98 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -10,7 +10,7 @@ dependencies = [ "gfx 0.0.1", "glfw 0.0.1 (git+https://github.com/servo/glfw-rs?ref=servo#955dbe919870b0536f79123232d87c0efe3c552e)", "glut 0.0.1 (git+https://github.com/servo/rust-glut#01af0162ea0322ad1a40d6adb023a39813605949)", - "js 0.1.0 (git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04)", + "js 0.1.0 (git+https://github.com/servo/rust-mozjs#750d714df96e2f5b810a2080e4c1a3c9c62d6985)", "layers 0.1.0 (git+https://github.com/servo/rust-layers#7559e747a1ca375449d959bea8262aa906d0bf47)", "msg 0.0.1", "net 0.0.1", @@ -269,9 +269,9 @@ dependencies = [ [[package]] name = "js" version = "0.1.0" -source = "git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04" +source = "git+https://github.com/servo/rust-mozjs#750d714df96e2f5b810a2080e4c1a3c9c62d6985" dependencies = [ - "mozjs-sys 0.0.0 (git+https://github.com/servo/mozjs#47cd6a4e60c75642ba182f0df9a42b71ec7c2c88)", + "mozjs-sys 0.0.0 (git+https://github.com/servo/mozjs#526e23021805b26f8341e5e580b7ffbfc635d359)", ] [[package]] @@ -323,7 +323,7 @@ source = "git+https://github.com/Kimundi/lazy-static.rs#e62a65372f1dd9019e37eb93 [[package]] name = "mozjs-sys" version = "0.0.0" -source = "git+https://github.com/servo/mozjs#47cd6a4e60c75642ba182f0df9a42b71ec7c2c88" +source = "git+https://github.com/servo/mozjs#526e23021805b26f8341e5e580b7ffbfc635d359" [[package]] name = "msg" @@ -404,7 +404,7 @@ dependencies = [ "gfx 0.0.1", "http 0.1.0-pre (git+https://github.com/servo/rust-http?ref=servo#92019011b0cdf1bffc8c584830de1bf330d79d0d)", "hubbub 0.1.0 (git+https://github.com/servo/rust-hubbub#c7f868e688de6e9cbdc26aa09292ed072bc2648b)", - "js 0.1.0 (git+https://github.com/servo/rust-mozjs#41fb0d80a5ed5614ca13a120cdb3281e599d4e04)", + "js 0.1.0 (git+https://github.com/servo/rust-mozjs#750d714df96e2f5b810a2080e4c1a3c9c62d6985)", "msg 0.0.1", "net 0.0.1", "plugins 0.0.1", diff --git a/src/lib.rs b/src/lib.rs index 6434f0c364c2..2c875cfd57e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,7 @@ #![comment = "The Servo Parallel Browser Project"] #![license = "MPL"] -#![feature(globs, macro_rules, phase, thread_local)] +#![feature(globs, macro_rules, phase, thread_local, unsafe_destructor)] #![deny(unused_imports, unused_variable)] @@ -92,6 +92,8 @@ pub fn run(opts: opts::Opts) { pool_config.event_loop_factory = rustuv::event_loop; let mut pool = green::SchedPool::new(pool_config); + script::init(); + let (compositor_port, compositor_chan) = CompositorChan::new(); let time_profiler_chan = TimeProfiler::create(opts.time_profiler_period); let memory_profiler_chan = MemoryProfiler::create(opts.memory_profiler_period); @@ -158,5 +160,7 @@ pub fn run(opts: opts::Opts) { memory_profiler_chan); pool.shutdown(); + + script::shutdown(); } diff --git a/tests/content/test_global.html b/tests/content/test_global.html index 24cfbc5f6ba8..18afe998340d 100644 --- a/tests/content/test_global.html +++ b/tests/content/test_global.html @@ -2,6 +2,7 @@