aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/bindings
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/bindings')
-rw-r--r--components/script/dom/bindings/callback.rs117
-rw-r--r--components/script/dom/bindings/cell.rs4
-rw-r--r--components/script/dom/bindings/codegen/Bindings.conf2
-rw-r--r--components/script/dom/bindings/codegen/CodegenRust.py1454
-rw-r--r--components/script/dom/bindings/codegen/Configuration.py8
-rw-r--r--components/script/dom/bindings/conversions.rs368
-rw-r--r--components/script/dom/bindings/error.rs47
-rw-r--r--components/script/dom/bindings/global.rs41
-rw-r--r--components/script/dom/bindings/js.rs543
-rw-r--r--components/script/dom/bindings/proxyhandler.rs139
-rw-r--r--components/script/dom/bindings/refcounted.rs33
-rw-r--r--components/script/dom/bindings/structuredclone.rs15
-rw-r--r--components/script/dom/bindings/trace.rs227
-rw-r--r--components/script/dom/bindings/utils.rs378
14 files changed, 1810 insertions, 1566 deletions
diff --git a/components/script/dom/bindings/callback.rs b/components/script/dom/bindings/callback.rs
index 4baccae098e..bc6077c8cb7 100644
--- a/components/script/dom/bindings/callback.rs
+++ b/components/script/dom/bindings/callback.rs
@@ -6,15 +6,22 @@
use dom::bindings::error::{Fallible, Error};
use dom::bindings::global::global_object_for_js_object;
-use dom::bindings::js::JSRef;
use dom::bindings::utils::Reflectable;
-use js::jsapi::{JSContext, JSObject, JS_WrapObject, JS_ObjectIsCallable, JS_GetGlobalObject};
+use js::jsapi::{JSContext, JSObject, JS_WrapObject, IsCallable};
use js::jsapi::{JS_GetProperty, JS_IsExceptionPending, JS_ReportPendingException};
+use js::jsapi::{RootedObject, RootedValue, MutableHandleObject, Heap};
+use js::jsapi::{JSAutoCompartment};
+use js::jsapi::{JS_BeginRequest, JS_EndRequest};
+use js::jsapi::{JS_EnterCompartment, JS_LeaveCompartment, JSCompartment};
+use js::jsapi::GetGlobalForObjectCrossCompartment;
+use js::jsapi::{JS_SaveFrameChain, JS_RestoreFrameChain};
use js::jsval::{JSVal, UndefinedValue};
-use js::rust::with_compartment;
use std::ffi::CString;
use std::ptr;
+use std::rc::Rc;
+use std::intrinsics::return_address;
+use std::default::Default;
/// The exception handling used for a call.
#[derive(Copy, Clone, PartialEq)]
@@ -26,7 +33,7 @@ pub enum ExceptionHandling {
}
/// A common base class for representing IDL callback function types.
-#[derive(Copy, Clone,PartialEq)]
+#[derive(PartialEq)]
#[jstraceable]
pub struct CallbackFunction {
object: CallbackObject
@@ -34,17 +41,23 @@ pub struct CallbackFunction {
impl CallbackFunction {
/// Create a new `CallbackFunction` for this object.
- pub fn new(callback: *mut JSObject) -> CallbackFunction {
+ pub fn new() -> CallbackFunction {
CallbackFunction {
object: CallbackObject {
- callback: callback
+ callback: Heap::default()
}
}
}
+
+ /// Initialize the callback function with a value.
+ /// Should be called once this object is done moving.
+ pub fn init(&mut self, callback: *mut JSObject) {
+ self.object.callback.set(callback);
+ }
}
/// A common base class for representing IDL callback interface types.
-#[derive(Copy, Clone,PartialEq)]
+#[derive(PartialEq)]
#[jstraceable]
pub struct CallbackInterface {
object: CallbackObject
@@ -53,18 +66,23 @@ pub struct CallbackInterface {
/// A common base class for representing IDL callback function and
/// callback interface types.
#[allow(raw_pointer_derive)]
-#[derive(Copy, Clone,PartialEq)]
#[jstraceable]
struct CallbackObject {
/// The underlying `JSObject`.
- callback: *mut JSObject,
+ callback: Heap<*mut JSObject>,
+}
+
+impl PartialEq for CallbackObject {
+ fn eq(&self, other: &CallbackObject) -> bool {
+ self.callback.get() == other.callback.get()
+ }
}
/// A trait to be implemented by concrete IDL callback function and
/// callback interface types.
pub trait CallbackContainer {
/// Create a new CallbackContainer object for the given `JSObject`.
- fn new(callback: *mut JSObject) -> Self;
+ fn new(callback: *mut JSObject) -> Rc<Self>;
/// Returns the underlying `JSObject`.
fn callback(&self) -> *mut JSObject;
}
@@ -72,83 +90,103 @@ pub trait CallbackContainer {
impl CallbackInterface {
/// Returns the underlying `JSObject`.
pub fn callback(&self) -> *mut JSObject {
- self.object.callback
+ self.object.callback.get()
}
}
impl CallbackFunction {
/// Returns the underlying `JSObject`.
pub fn callback(&self) -> *mut JSObject {
- self.object.callback
+ self.object.callback.get()
}
}
impl CallbackInterface {
/// Create a new CallbackInterface object for the given `JSObject`.
- pub fn new(callback: *mut JSObject) -> CallbackInterface {
+ pub fn new() -> CallbackInterface {
CallbackInterface {
object: CallbackObject {
- callback: callback
+ callback: Heap::default()
}
}
}
+ /// Initialize the callback function with a value.
+ /// Should be called once this object is done moving.
+ pub fn init(&mut self, callback: *mut JSObject) {
+ self.object.callback.set(callback);
+ }
+
/// Returns the property with the given `name`, if it is a callable object,
/// or an error otherwise.
pub fn get_callable_property(&self, cx: *mut JSContext, name: &str)
-> Fallible<JSVal> {
- let mut callable = UndefinedValue();
+ let mut callable = RootedValue::new(cx, UndefinedValue());
+ let obj = RootedObject::new(cx, self.callback());
unsafe {
let c_name = CString::new(name).unwrap();
- if JS_GetProperty(cx, self.callback(), c_name.as_ptr(), &mut callable) == 0 {
+ if JS_GetProperty(cx, obj.handle(), c_name.as_ptr(),
+ callable.handle_mut()) == 0 {
return Err(Error::JSFailed);
}
- if !callable.is_object() ||
- JS_ObjectIsCallable(cx, callable.to_object()) == 0 {
+ if !callable.ptr.is_object() ||
+ IsCallable(callable.ptr.to_object()) == 0 {
return Err(Error::Type(
format!("The value of the {} property is not callable", name)));
}
}
- Ok(callable)
+ Ok(callable.ptr)
}
}
/// Wraps the reflector for `p` into the compartment of `cx`.
pub fn wrap_call_this_object<T: Reflectable>(cx: *mut JSContext,
- p: JSRef<T>) -> *mut JSObject {
- let mut obj = p.reflector().get_jsobject();
- assert!(!obj.is_null());
+ p: &T,
+ mut rval: MutableHandleObject) {
+ rval.set(p.reflector().get_jsobject().get());
+ assert!(!rval.get().is_null());
unsafe {
- if JS_WrapObject(cx, &mut obj) == 0 {
- return ptr::null_mut();
+ if JS_WrapObject(cx, rval) == 0 {
+ rval.set(ptr::null_mut());
}
}
-
- return obj;
}
/// A class that performs whatever setup we need to safely make a call while
/// this class is on the stack. After `new` returns, the call is safe to make.
pub struct CallSetup {
+ /// The compartment for reporting exceptions.
+ /// As a RootedObject, this must be the first field in order to
+ /// determine the final address on the stack correctly.
+ exception_compartment: RootedObject,
/// The `JSContext` used for the call.
cx: *mut JSContext,
+ /// The compartment we were in before the call.
+ old_compartment: *mut JSCompartment,
/// The exception handling used for the call.
- _handling: ExceptionHandling,
+ handling: ExceptionHandling,
}
impl CallSetup {
/// Performs the setup needed to make a call.
#[allow(unrooted_must_root)]
- pub fn new<T: CallbackContainer>(callback: T, handling: ExceptionHandling) -> CallSetup {
+ pub fn new<T: CallbackContainer>(callback: &T, handling: ExceptionHandling) -> CallSetup {
let global = global_object_for_js_object(callback.callback());
- let global = global.root();
let cx = global.r().get_cx();
+ unsafe { JS_BeginRequest(cx); }
+ let exception_compartment = unsafe {
+ GetGlobalForObjectCrossCompartment(callback.callback())
+ };
CallSetup {
+ exception_compartment:
+ RootedObject::new_with_addr(cx, exception_compartment,
+ unsafe { return_address() }),
cx: cx,
- _handling: handling,
+ old_compartment: unsafe { JS_EnterCompartment(cx, callback.callback()) },
+ handling: handling,
}
}
@@ -160,14 +198,23 @@ impl CallSetup {
impl Drop for CallSetup {
fn drop(&mut self) {
- let need_to_deal_with_exception = unsafe { JS_IsExceptionPending(self.cx) } != 0;
+ unsafe { JS_LeaveCompartment(self.cx, self.old_compartment); }
+ let need_to_deal_with_exception =
+ self.handling == ExceptionHandling::Report &&
+ unsafe { JS_IsExceptionPending(self.cx) } != 0;
if need_to_deal_with_exception {
unsafe {
- let old_global = JS_GetGlobalObject(self.cx);
- with_compartment(self.cx, old_global, || {
- JS_ReportPendingException(self.cx)
- });
+ let old_global = RootedObject::new(self.cx, self.exception_compartment.ptr);
+ let saved = JS_SaveFrameChain(self.cx) != 0;
+ {
+ let _ac = JSAutoCompartment::new(self.cx, old_global.ptr);
+ JS_ReportPendingException(self.cx);
+ }
+ if saved {
+ JS_RestoreFrameChain(self.cx);
+ }
}
}
+ unsafe { JS_EndRequest(self.cx); }
}
}
diff --git a/components/script/dom/bindings/cell.rs b/components/script/dom/bindings/cell.rs
index 177fed9397b..6513e250166 100644
--- a/components/script/dom/bindings/cell.rs
+++ b/components/script/dom/bindings/cell.rs
@@ -40,7 +40,9 @@ impl<T> DOMRefCell<T> {
/// so you have to be careful in trace code!
#[allow(unsafe_code)]
pub unsafe fn borrow_for_gc_trace<'a>(&'a self) -> &'a T {
- debug_assert!(task_state::get().contains(SCRIPT | IN_GC));
+ // FIXME: IN_GC isn't reliable enough - doesn't catch minor GCs
+ // https://github.com/servo/servo/issues/6389
+ //debug_assert!(task_state::get().contains(SCRIPT | IN_GC));
&*self.value.as_unsafe_cell().get()
}
diff --git a/components/script/dom/bindings/codegen/Bindings.conf b/components/script/dom/bindings/codegen/Bindings.conf
index 439ddfbd59e..48b6067d00c 100644
--- a/components/script/dom/bindings/codegen/Bindings.conf
+++ b/components/script/dom/bindings/codegen/Bindings.conf
@@ -15,7 +15,7 @@
DOMInterfaces = {
'Window': {
- 'outerObjectHook': 'Some(bindings::utils::outerize_global as extern fn(*mut JSContext, JSHandleObject) -> *mut JSObject)',
+ 'outerObjectHook': 'Some(bindings::utils::outerize_global)',
},
#FIXME(jdm): This should be 'register': False, but then we don't generate enum types
diff --git a/components/script/dom/bindings/codegen/CodegenRust.py b/components/script/dom/bindings/codegen/CodegenRust.py
index aa1b1ae14d3..f9e929c68da 100644
--- a/components/script/dom/bindings/codegen/CodegenRust.py
+++ b/components/script/dom/bindings/codegen/CodegenRust.py
@@ -8,12 +8,15 @@ import operator
import os
import re
import string
+import textwrap
+import functools
from WebIDL import (
BuiltinTypes,
IDLBuiltinType,
IDLNullValue,
IDLType,
+ IDLInterfaceMember,
IDLUndefinedValue,
)
@@ -103,15 +106,16 @@ class CastableObjectUnwrapper():
codeOnFailure is the code to run if unwrapping fails.
"""
- def __init__(self, descriptor, source, codeOnFailure):
+ def __init__(self, descriptor, source, codeOnFailure, handletype):
self.substitution = {
"source": source,
"codeOnFailure": CGIndenter(CGGeneric(codeOnFailure), 8).define(),
+ "handletype": handletype,
}
def __str__(self):
return string.Template("""\
-match native_from_reflector_jsmanaged(${source}) {
+match native_from_handle${handletype}(${source}) {
Ok(val) => val,
Err(()) => {
${codeOnFailure}
@@ -119,6 +123,136 @@ ${codeOnFailure}
}""").substitute(self.substitution)
+# We'll want to insert the indent at the beginnings of lines, but we
+# don't want to indent empty lines. So only indent lines that have a
+# non-newline character on them.
+lineStartDetector = re.compile("^(?=[^\n#])", re.MULTILINE)
+
+
+def indent(s, indentLevel=2):
+ """
+ Indent C++ code.
+
+ Weird secret feature: this doesn't indent lines that start with # (such as
+ #include lines or #ifdef/#endif).
+ """
+ if s == "":
+ return s
+ return re.sub(lineStartDetector, indentLevel * " ", s)
+
+
+# dedent() and fill() are often called on the same string multiple
+# times. We want to memoize their return values so we don't keep
+# recomputing them all the time.
+def memoize(fn):
+ """
+ Decorator to memoize a function of one argument. The cache just
+ grows without bound.
+ """
+ cache = {}
+ @functools.wraps(fn)
+ def wrapper(arg):
+ retval = cache.get(arg)
+ if retval is None:
+ retval = cache[arg] = fn(arg)
+ return retval
+ return wrapper
+
+@memoize
+def dedent(s):
+ """
+ Remove all leading whitespace from s, and remove a blank line
+ at the beginning.
+ """
+ if s.startswith('\n'):
+ s = s[1:]
+ return textwrap.dedent(s)
+
+
+# This works by transforming the fill()-template to an equivalent
+# string.Template.
+fill_multiline_substitution_re = re.compile(r"( *)\$\*{(\w+)}(\n)?")
+
+
+@memoize
+def compile_fill_template(template):
+ """
+ Helper function for fill(). Given the template string passed to fill(),
+ do the reusable part of template processing and return a pair (t,
+ argModList) that can be used every time fill() is called with that
+ template argument.
+
+ argsModList is list of tuples that represent modifications to be
+ made to args. Each modification has, in order: i) the arg name,
+ ii) the modified name, iii) the indent depth.
+ """
+ t = dedent(template)
+ assert t.endswith("\n") or "\n" not in t
+ argModList = []
+
+ def replace(match):
+ """
+ Replaces a line like ' $*{xyz}\n' with '${xyz_n}',
+ where n is the indent depth, and add a corresponding entry to
+ argModList.
+
+ Note that this needs to close over argModList, so it has to be
+ defined inside compile_fill_template().
+ """
+ indentation, name, nl = match.groups()
+ depth = len(indentation)
+
+ # Check that $*{xyz} appears by itself on a line.
+ prev = match.string[:match.start()]
+ if (prev and not prev.endswith("\n")) or nl is None:
+ raise ValueError("Invalid fill() template: $*{%s} must appear by itself on a line" % name)
+
+ # Now replace this whole line of template with the indented equivalent.
+ modified_name = name + "_" + str(depth)
+ argModList.append((name, modified_name, depth))
+ return "${" + modified_name + "}"
+
+ t = re.sub(fill_multiline_substitution_re, replace, t)
+ return (string.Template(t), argModList)
+
+def fill(template, **args):
+ """
+ Convenience function for filling in a multiline template.
+
+ `fill(template, name1=v1, name2=v2)` is a lot like
+ `string.Template(template).substitute({"name1": v1, "name2": v2})`.
+
+ However, it's shorter, and has a few nice features:
+
+ * If `template` is indented, fill() automatically dedents it!
+ This makes code using fill() with Python's multiline strings
+ much nicer to look at.
+
+ * If `template` starts with a blank line, fill() strips it off.
+ (Again, convenient with multiline strings.)
+
+ * fill() recognizes a special kind of substitution
+ of the form `$*{name}`.
+
+ Use this to paste in, and automatically indent, multiple lines.
+ (Mnemonic: The `*` is for "multiple lines").
+
+ A `$*` substitution must appear by itself on a line, with optional
+ preceding indentation (spaces only). The whole line is replaced by the
+ corresponding keyword argument, indented appropriately. If the
+ argument is an empty string, no output is generated, not even a blank
+ line.
+ """
+
+ t, argModList = compile_fill_template(template)
+ # Now apply argModList to args
+ for (name, modified_name, depth) in argModList:
+ if not (args[name] == "" or args[name].endswith("\n")):
+ raise ValueError("Argument %s with value %r is missing a newline" % (name, args[name]))
+ args[modified_name] = indent(args[name], depth)
+
+ return t.substitute(args)
+
class CGThing():
"""
Abstract base class for things that spit out code.
@@ -232,14 +366,13 @@ class CGMethodCall(CGThing):
# Doesn't matter which of the possible signatures we use, since
# they all have the same types up to that point; just use
# possibleSignatures[0]
- caseBody = [CGGeneric("let argv_start = JS_ARGV(cx, vp);")]
- caseBody.extend([ CGArgumentConverter(possibleSignatures[0][1][i],
- i, "argv_start", "argc",
+ caseBody = [ CGArgumentConverter(possibleSignatures[0][1][i],
+ i, "args", "argc",
descriptor) for i in
- range(0, distinguishingIndex) ])
+ range(0, distinguishingIndex) ]
# Select the right overload from our set.
- distinguishingArg = "(*argv_start.offset(%d))" % distinguishingIndex
+ distinguishingArg = "args.get(%d)" % distinguishingIndex
def pickFirstSignature(condition, filterLambda):
sigs = filter(filterLambda, possibleSignatures)
@@ -282,7 +415,7 @@ class CGMethodCall(CGThing):
# also allow the unwrapping test to skip having to do codegen
# for the null-or-undefined case, which we already handled
# above.
- caseBody.append(CGGeneric("if (%s).is_object() {" %
+ caseBody.append(CGGeneric("if %s.get().is_object() {" %
(distinguishingArg)))
for idx, sig in enumerate(interfacesSigs):
caseBody.append(CGIndenter(CGGeneric("loop {")));
@@ -319,7 +452,7 @@ class CGMethodCall(CGThing):
# XXXbz Now we're supposed to check for distinguishingArg being
# an array or a platform object that supports indexed
# properties... skip that last for now. It's a bit of a pain.
- pickFirstSignature("%s.isObject() && IsArrayLike(cx, &%s.toObject())" %
+ pickFirstSignature("%s.get().isObject() && IsArrayLike(cx, &%s.get().toObject())" %
(distinguishingArg, distinguishingArg),
lambda s:
(s[1][distinguishingIndex].type.isArray() or
@@ -328,14 +461,14 @@ class CGMethodCall(CGThing):
# Check for Date objects
# XXXbz Do we need to worry about security wrappers around the Date?
- pickFirstSignature("%s.isObject() && JS_ObjectIsDate(cx, &%s.toObject())" %
+ pickFirstSignature("%s.get().isObject() && JS_ObjectIsDate(cx, &%s.get().toObject())" %
(distinguishingArg, distinguishingArg),
lambda s: (s[1][distinguishingIndex].type.isDate() or
s[1][distinguishingIndex].type.isObject()))
# Check for vanilla JS objects
# XXXbz Do we need to worry about security wrappers?
- pickFirstSignature("%s.is_object() && !is_platform_object(%s.to_object())" %
+ pickFirstSignature("%s.get().is_object() && !is_platform_object(%s.get().to_object())" %
(distinguishingArg, distinguishingArg),
lambda s: (s[1][distinguishingIndex].type.isCallback() or
s[1][distinguishingIndex].type.isCallbackInterface() or
@@ -524,7 +657,7 @@ def getJSToNativeConversionInfo(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 JSFalse;"
needsRooting = typeNeedsRooting(type, descriptorProvider)
@@ -581,11 +714,11 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
# Handle the non-object cases by wrapping up the whole
# thing in an if cascade.
templateBody = (
- "if (${val}).is_object() {\n" +
+ "if ${val}.get().is_object() {\n" +
CGIndenter(CGGeneric(templateBody)).define() + "\n")
if type.nullable():
templateBody += (
- "} else if (${val}).is_null_or_undefined() {\n"
+ "} else if ${val}.get().is_null_or_undefined() {\n"
" %s\n") % nullValue
templateBody += (
"} else {\n" +
@@ -621,8 +754,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if descriptor.interface.isCallback():
name = descriptor.nativeType
- declType = CGGeneric(name)
- template = "%s::new((${val}).to_object())" % name
+ declType = CGWrapper(CGGeneric(name), pre="Rc<", post=">")
+ template = "%s::new(${val}.get().to_object())" % name
if type.nullable():
declType = CGWrapper(declType, pre="Option<", post=">")
template = wrapObjectTemplate("Some(%s)" % template, "None",
@@ -658,17 +791,15 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
templateBody = str(CastableObjectUnwrapper(
descriptor,
- "(${val}).to_object()",
- unwrapFailureCode))
+ "${val}",
+ unwrapFailureCode,
+ "value"))
declType = CGGeneric(descriptorType)
if type.nullable():
templateBody = "Some(%s)" % templateBody
declType = CGWrapper(declType, pre="Option<", post=">")
- if isMember:
- templateBody += ".root()"
-
templateBody = wrapObjectTemplate(templateBody, "None",
isDefinitelyObject, type, failureCode)
@@ -681,8 +812,8 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not isEnforceRange and not isClamp
treatAs = {
- "Default": "Default",
- "EmptyString": "Empty",
+ "Default": "StringificationBehavior::Default",
+ "EmptyString": "StringificationBehavior::Empty",
}
if treatNullAs not in treatAs:
raise TypeError("We don't support [TreatNullAs=%s]" % treatNullAs)
@@ -794,23 +925,25 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
assert not type.treatNonObjectAsNull() or not type.treatNonCallableAsNull()
declType = CGGeneric('%s::%s' % (type.unroll().module(), type.unroll().identifier.name))
+ finalDeclType = CGTemplatedType("Rc", declType)
conversion = CGCallbackTempRoot(declType.define())
if type.nullable():
declType = CGTemplatedType("Option", declType)
+ finalDeclType = CGTemplatedType("Option", finalDeclType)
conversion = CGWrapper(conversion, pre="Some(", post=")")
if allowTreatNonObjectAsNull and type.treatNonObjectAsNull():
if not isDefinitelyObject:
- haveObject = "${val}.is_object()"
+ haveObject = "${val}.get().is_object()"
template = CGIfElseWrapper(haveObject,
conversion,
CGGeneric("None")).define()
else:
template = conversion
else:
- template = CGIfElseWrapper("JS_ObjectIsCallable(cx, ${val}.to_object()) != 0",
+ template = CGIfElseWrapper("IsCallable(${val}.get().to_object()) != 0",
conversion,
onFailureNotCallable(failureCode)).define()
template = wrapObjectTemplate(
@@ -829,29 +962,47 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
else:
default = None
- return JSToNativeConversionInfo(template, default, declType, needsRooting=needsRooting)
+ return JSToNativeConversionInfo(template, default, finalDeclType, needsRooting=needsRooting)
if type.isAny():
assert not isEnforceRange and not isClamp
- declType = CGGeneric("JSVal")
-
- if defaultValue is None:
- default = None
- elif isinstance(defaultValue, IDLNullValue):
- default = "NullValue()"
- elif isinstance(defaultValue, IDLUndefinedValue):
- default = "UndefinedValue()"
+ declType = ""
+ default = ""
+ if isMember == "Dictionary":
+ # TODO: Need to properly root dictionaries
+ # https://github.com/servo/servo/issues/6381
+ declType = CGGeneric("JSVal")
+
+ if defaultValue is None:
+ default = None
+ elif isinstance(defaultValue, IDLNullValue):
+ default = "NullValue()"
+ elif isinstance(defaultValue, IDLUndefinedValue):
+ default = "UndefinedValue()"
+ else:
+ raise TypeError("Can't handle non-null, non-undefined default value here")
else:
- raise TypeError("Can't handle non-null, non-undefined default value here")
+ declType = CGGeneric("HandleValue")
+
+ if defaultValue is None:
+ default = None
+ elif isinstance(defaultValue, IDLNullValue):
+ default = "HandleValue::null()"
+ elif isinstance(defaultValue, IDLUndefinedValue):
+ default = "HandleValue::undefined()"
+ else:
+ raise TypeError("Can't handle non-null, non-undefined default value here")
return handleOptional("${val}", declType, default)
if type.isObject():
assert not isEnforceRange and not isClamp
+ # TODO: Need to root somehow
+ # https://github.com/servo/servo/issues/6382
declType = CGGeneric("*mut JSObject")
- templateBody = wrapObjectTemplate("${val}.to_object()",
+ templateBody = wrapObjectTemplate("${val}.get().to_object()",
"ptr::null_mut()",
isDefinitelyObject, type, failureCode)
@@ -871,7 +1022,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
" Err(_) => return 0,\n"
"}" % typeName)
- return handleOptional(template, declType, handleDefaultNull("%s::empty()" % typeName))
+ return handleOptional(template, declType, handleDefaultNull("%s::empty(cx)" % typeName))
if type.isVoid():
# This one only happens for return values, and its easy: Just
@@ -948,11 +1099,6 @@ def instantiateJSToNativeConversionTemplate(templateBody, replacements,
# conversion.
result.append(CGGeneric(""))
- if needsRooting:
- rootBody = "let %s = %s.root();" % (declName, declName)
- result.append(CGGeneric(rootBody))
- result.append(CGGeneric(""))
-
return result;
def convertConstIDLValueToJSVal(value):
@@ -979,7 +1125,7 @@ class CGArgumentConverter(CGThing):
argument list, and the argv and argc strings and generates code to
unwrap the argument to the right native type.
"""
- def __init__(self, argument, index, argv, argc, descriptorProvider,
+ def __init__(self, argument, index, args, argc, descriptorProvider,
invalidEnumValueFatal=True):
CGThing.__init__(self)
assert(not argument.defaultValue or argument.optional)
@@ -987,12 +1133,12 @@ class CGArgumentConverter(CGThing):
replacer = {
"index": index,
"argc": argc,
- "argv": argv
+ "args": args
}
condition = string.Template("${index} < ${argc}").substitute(replacer)
replacementVariables = {
- "val": string.Template("(*${argv}.offset(${index}))").substitute(replacer),
+ "val": string.Template("${args}.get(${index})").substitute(replacer),
}
info = getJSToNativeConversionInfo(
@@ -1032,7 +1178,7 @@ class CGArgumentConverter(CGThing):
else:
assert argument.optional
variadicConversion = {
- "val": string.Template("(*${argv}.offset(variadicArg as isize))").substitute(replacer),
+ "val": string.Template("${args}.get(variadicArg)").substitute(replacer),
}
innerConverter = instantiateJSToNativeConversionTemplate(
template, variadicConversion, declType, "slot",
@@ -1066,16 +1212,17 @@ class CGArgumentConverter(CGThing):
return self.converter.define()
-def wrapForType(jsvalRef, result='result', successCode='return 1;'):
+def wrapForType(jsvalRef, result='result', successCode='return 1;', pre=''):
"""
Reflect a Rust value into JS.
- * 'jsvalRef': a Rust reference to the JSVal in which to store the result
+ * 'jsvalRef': a MutableHandleValue in which to store the result
of the conversion;
* 'result': the name of the variable in which the Rust value is stored;
* 'successCode': the code to run once we have done the conversion.
+ * 'pre': code to run before the conversion if rooting is necessary
"""
- wrap = "%s = (%s).to_jsval(cx);" % (jsvalRef, result)
+ wrap = "%s\n(%s).to_jsval(cx, %s);" % (pre, result, jsvalRef)
if successCode:
wrap += "\n%s" % successCode
return wrap
@@ -1142,8 +1289,8 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
result = CGWrapper(result, pre="Option<", post=">")
return result
if returnType.isCallback():
- result = CGGeneric('%s::%s' % (returnType.unroll().module(),
- returnType.unroll().identifier.name))
+ result = CGGeneric('Rc<%s::%s>' % (returnType.unroll().module(),
+ returnType.unroll().identifier.name))
if returnType.nullable():
result = CGWrapper(result, pre="Option<", post=">")
return result
@@ -1152,6 +1299,8 @@ def getRetvalDeclarationForType(returnType, descriptorProvider):
if returnType.nullable():
result = CGWrapper(result, pre="Option<", post=">")
return result
+ # TODO: Return the value through a MutableHandleValue outparam
+ # https://github.com/servo/servo/issues/6307
if returnType.isAny():
return CGGeneric("JSVal")
if returnType.isObject() or returnType.isSpiderMonkeyInterface():
@@ -1258,9 +1407,9 @@ class MethodDefiner(PropertyDefiner):
# 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',
+ self.regular.append({"name": '@@iterator',
"methodInfo": False,
- "nativeName": "JS_ArrayIterator",
+ "selfHostedName": "ArrayValues",
"length": 0,
"flags": "JSPROP_ENUMERATE" })
@@ -1280,21 +1429,31 @@ class MethodDefiner(PropertyDefiner):
return ""
def specData(m):
- if m.get("methodInfo", True):
- identifier = m.get("nativeName", m["name"])
- jitinfo = "&%s_methodinfo" % identifier
- accessor = "genericMethod as NonNullJSNative"
- else:
+ # TODO: Use something like JS_FNSPEC
+ # https://github.com/servo/servo/issues/6391
+ if "selfHostedName" in m:
+ selfHostedName = '%s as *const u8 as *const i8' % str_to_const_array(m["selfHostedName"])
+ assert not m.get("methodInfo", True)
+ accessor = "None"
jitinfo = "0 as *const JSJitInfo"
- accessor = m.get("nativeName", m["name"])
- if accessor[0:3] != 'JS_':
- accessor = "%s as NonNullJSNative" % accessor
- return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], m["flags"])
+ else:
+ selfHostedName = "0 as *const i8"
+ if m.get("methodInfo", True):
+ identifier = m.get("nativeName", m["name"])
+ jitinfo = "&%s_methodinfo" % identifier
+ accessor = "Some(genericMethod)"
+ else:
+ jitinfo = "0 as *const JSJitInfo"
+ accessor = 'Some(%s)' % m.get("nativeName", m["name"])
+ if m["name"].startswith("@@"):
+ return ('(SymbolCode::%s as i32 + 1)' % m["name"][2:], accessor, jitinfo, m["length"], m["flags"], selfHostedName)
+ return (str_to_const_array(m["name"]), accessor, jitinfo, m["length"], m["flags"], selfHostedName)
+
return self.generatePrefableArray(
array, name,
- ' JSFunctionSpec { name: %s 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 { name: %s as *const u8 as *const libc::c_char, call: JSNativeWrapper {op: %s, info: %s}, nargs: %s, flags: %s as u16, selfHostedName: %s }',
+ ' JSFunctionSpec { name: 0 as *const i8, call: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }, nargs: 0, flags: 0, selfHostedName: 0 as *const i8 }',
'JSFunctionSpec',
specData)
@@ -1314,12 +1473,12 @@ class AttrDefiner(PropertyDefiner):
return ""
def flags(attr):
- return "JSPROP_SHARED | JSPROP_ENUMERATE | JSPROP_NATIVE_ACCESSORS"
+ return "JSPROP_SHARED | JSPROP_ENUMERATE"
def getter(attr):
if self.static:
accessor = 'get_' + attr.identifier.name
- jitinfo = "0"
+ jitinfo = "0 as *const JSJitInfo"
else:
if attr.hasLenientThis():
accessor = "genericLenientGetter"
@@ -1327,17 +1486,17 @@ class AttrDefiner(PropertyDefiner):
accessor = "genericGetter"
jitinfo = "&%s_getterinfo" % attr.identifier.name
- return ("JSPropertyOpWrapper {op: Some(%(native)s as NonNullJSNative), info: %(info)s as *const JSJitInfo}"
+ return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
% {"info" : jitinfo,
"native" : accessor})
def setter(attr):
if attr.readonly and not attr.getExtendedAttribute("PutForwards"):
- return "JSStrictPropertyOpWrapper {op: None, info: 0 as *const JSJitInfo}"
+ return "JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }"
if self.static:
accessor = 'set_' + attr.identifier.name
- jitinfo = "0"
+ jitinfo = "0 as *const JSJitInfo"
else:
if attr.hasLenientThis():
accessor = "genericLenientSetter"
@@ -1345,7 +1504,7 @@ class AttrDefiner(PropertyDefiner):
accessor = "genericSetter"
jitinfo = "&%s_setterinfo" % attr.identifier.name
- return ("JSStrictPropertyOpWrapper {op: Some(%(native)s as NonNullJSNative), info: %(info)s as *const JSJitInfo}"
+ return ("JSNativeWrapper { op: Some(%(native)s), info: %(info)s }"
% {"info" : jitinfo,
"native" : accessor})
@@ -1355,8 +1514,8 @@ class AttrDefiner(PropertyDefiner):
return self.generatePrefableArray(
array, name,
- ' JSPropertySpec { name: %s 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 { name: %s as *const u8 as *const libc::c_char, flags: ((%s) & 0xFF) as u8, getter: %s, setter: %s }',
+ ' JSPropertySpec { name: 0 as *const i8, flags: 0, getter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo }, setter: JSNativeWrapper { op: None, info: 0 as *const JSJitInfo } }',
'JSPropertySpec',
specData)
@@ -1562,8 +1721,9 @@ class CGDOMJSClass(CGThing):
self.descriptor = descriptor
def define(self):
- traceHook = 'Some(%s as unsafe extern "C" fn(*mut JSTracer, *mut JSObject))' % TRACE_HOOK_NAME
+ traceHook = 'Some(%s)' % TRACE_HOOK_NAME
if self.descriptor.isGlobal():
+ traceHook = "Some(js::jsapi::_Z24JS_GlobalObjectTraceHookP8JSTracerP8JSObject)"
flags = "JSCLASS_IS_GLOBAL | JSCLASS_DOM_GLOBAL"
slots = "JSCLASS_GLOBAL_SLOT_COUNT + 1"
else:
@@ -1571,66 +1731,54 @@ class CGDOMJSClass(CGThing):
slots = "1"
return """\
static Class: DOMJSClass = DOMJSClass {
- base: js::Class {
+ base: js::jsapi::Class {
name: %s as *const u8 as *const libc::c_char,
- flags: JSCLASS_IS_DOMJSCLASS | %s | (((%s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT), //JSCLASS_HAS_RESERVED_SLOTS(%s),
- addProperty: Some(JS_PropertyStub),
- delProperty: Some(JS_PropertyStub),
- getProperty: Some(JS_PropertyStub),
- setProperty: Some(JS_StrictPropertyStub),
- enumerate: Some(JS_EnumerateStub),
- resolve: Some(JS_ResolveStub),
- convert: Some(JS_ConvertStub),
- finalize: Some(%s as unsafe extern "C" fn(*mut JSFreeOp, *mut JSObject)),
- checkAccess: None,
+ flags: JSCLASS_IS_DOMJSCLASS | JSCLASS_IMPLEMENTS_BARRIERS | %s | (((%s) & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT), //JSCLASS_HAS_RESERVED_SLOTS(%s),
+ addProperty: None,
+ delProperty: None,
+ getProperty: None,
+ setProperty: None,
+ enumerate: None,
+ resolve: None,
+ convert: None,
+ finalize: Some(%s),
call: None,
hasInstance: None,
construct: None,
trace: %s,
- ext: js::ClassExtension {
- equality: 0 as *const u8,
+ spec: js::jsapi::ClassSpec {
+ createConstructor: None,
+ createPrototype: None,
+ constructorFunctions: 0 as *const js::jsapi::JSFunctionSpec,
+ constructorProperties: 0 as *const js::jsapi::JSPropertySpec,
+ prototypeFunctions: 0 as *const js::jsapi::JSFunctionSpec,
+ prototypeProperties: 0 as *const js::jsapi::JSPropertySpec,
+ finishInit: None,
+ flags: 0,
+ },
+
+ ext: js::jsapi::ClassExtension {
outerObject: %s,
innerObject: None,
- iteratorObject: 0 as *const u8,
- unused: 0 as *const u8,
- isWrappedNative: 0 as *const u8,
+ isWrappedNative: 0,
+ weakmapKeyDelegateOp: None,
+ objectMovedOp: 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,
-
- enumerate: 0 as *const u8,
- typeOf: 0 as *const u8,
+ ops: js::jsapi::ObjectOps {
+ lookupProperty: None,
+ defineProperty: None,
+ hasProperty: None,
+ getProperty: None,
+ setProperty: None,
+ getOwnPropertyDescriptor: None,
+ deleteProperty: None,
+ watch: None,
+ unwatch: None,
+ getElements: None,
+ enumerate: None,
thisObject: %s,
- clear: 0 as *const u8,
},
},
dom_class: %s
@@ -1640,7 +1788,7 @@ static Class: DOMJSClass = DOMJSClass {
FINALIZE_HOOK_NAME, traceHook,
self.descriptor.outerObjectHook,
self.descriptor.outerObjectHook,
- CGIndenter(CGGeneric(DOMClass(self.descriptor))).define())
+ CGGeneric(DOMClass(self.descriptor)).define())
def str_to_const_array(s):
return "b\"%s\\0\"" % s
@@ -1655,20 +1803,19 @@ class CGPrototypeJSClass(CGThing):
static PrototypeClass: JSClass = JSClass {
name: %s as *const u8 as *const libc::c_char,
flags: (1 & JSCLASS_RESERVED_SLOTS_MASK) << JSCLASS_RESERVED_SLOTS_SHIFT, //JSCLASS_HAS_RESERVED_SLOTS(1)
- addProperty: Some(JS_PropertyStub),
- delProperty: Some(JS_PropertyStub),
- getProperty: Some(JS_PropertyStub),
- setProperty: Some(JS_StrictPropertyStub),
- enumerate: Some(JS_EnumerateStub),
- resolve: Some(JS_ResolveStub),
- convert: Some(JS_ConvertStub),
+ addProperty: None,
+ delProperty: None,
+ getProperty: None,
+ setProperty: None,
+ enumerate: None,
+ resolve: None,
+ convert: None,
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; 25]
};
""" % str_to_const_array(self.descriptor.interface.identifier.name + "Prototype")
@@ -1742,13 +1889,7 @@ class CGGeneric(CGThing):
class CGCallbackTempRoot(CGGeneric):
def __init__(self, name):
- val = "%s::new(tempRoot)" % name
- define = """\
-{
- let tempRoot = ${val}.to_object();
- %s
-}""" % val
- CGGeneric.__init__(self, define)
+ CGGeneric.__init__(self, "%s::new(${val}.get().to_object())" % name)
def getAllTypes(descriptors, dictionaries, callbacks):
@@ -1792,12 +1933,13 @@ def UnionTypes(descriptors, dictionaries, callbacks, config):
'dom::bindings::codegen::PrototypeList',
'dom::bindings::conversions::FromJSValConvertible',
'dom::bindings::conversions::ToJSValConvertible',
- 'dom::bindings::conversions::native_from_reflector_jsmanaged',
- 'dom::bindings::conversions::StringificationBehavior::Default',
+ 'dom::bindings::conversions::native_from_handlevalue',
+ 'dom::bindings::conversions::StringificationBehavior',
'dom::bindings::error::throw_not_in_union',
- 'dom::bindings::js::Unrooted',
+ 'dom::bindings::js::Root',
'dom::types::*',
'js::jsapi::JSContext',
+ 'js::jsapi::{HandleValue, MutableHandleValue}',
'js::jsval::JSVal',
'util::str::DOMString',
]
@@ -1917,32 +2059,36 @@ class CGAbstractMethod(CGThing):
assert(False) # Override me!
def CreateBindingJSObject(descriptor, parent=None):
- create = "let mut raw: Unrooted<%s> = Unrooted::from_raw(&*object);\n" % descriptor.concreteType
+ create = "let mut raw = boxed::into_raw(object);\nlet _rt = RootedTraceable::new(&*raw);\n"
if descriptor.proxy:
assert not descriptor.isGlobal()
create += """
let handler = RegisterBindings::proxy_handlers[PrototypeList::Proxies::%s as usize];
-let mut private = PrivateValue(boxed::into_raw(object) as *const libc::c_void);
-let obj = with_compartment(cx, proto, || {
+let private = RootedValue::new(cx, PrivateValue(raw as *const libc::c_void));
+let obj = {
+ let _ac = JSAutoCompartment::new(cx, proto.ptr);
NewProxyObject(cx, handler,
- &private,
- proto, %s,
+ private.handle(),
+ proto.ptr, %s.get(),
ptr::null_mut(), ptr::null_mut())
-});
-assert!(!obj.is_null());\
+};
+assert!(!obj.is_null());
+let obj = RootedObject::new(cx, obj);\
""" % (descriptor.name, parent)
else:
if descriptor.isGlobal():
- create += "let obj = create_dom_global(cx, &Class.base as *const js::Class as *const JSClass);\n"
+ create += "let obj = RootedObject::new(cx, create_dom_global(cx, &Class.base as *const js::jsapi::Class as *const JSClass, Some(%s)));\n" % TRACE_HOOK_NAME
else:
- create += ("let obj = with_compartment(cx, proto, || {\n"
- " JS_NewObject(cx, &Class.base as *const js::Class as *const JSClass, &*proto, &*%s)\n"
- "});\n" % parent)
+ create += ("let obj = {\n"
+ " let _ac = JSAutoCompartment::new(cx, proto.ptr);\n"
+ " JS_NewObjectWithGivenProto(cx, &Class.base as *const js::jsapi::Class as *const JSClass, proto.handle())\n"
+ "};\n"
+ "let obj = RootedObject::new(cx, obj);\n")
create += """\
-assert!(!obj.is_null());
+assert!(!obj.ptr.is_null());
-JS_SetReservedSlot(obj, DOM_OBJECT_SLOT,
- PrivateValue(boxed::into_raw(object) as *const libc::c_void));"""
+JS_SetReservedSlot(obj.ptr, DOM_OBJECT_SLOT,
+ PrivateValue(raw as *const libc::c_void));"""
return create
class CGWrapMethod(CGAbstractMethod):
@@ -1958,37 +2104,46 @@ class CGWrapMethod(CGAbstractMethod):
else:
args = [Argument('*mut JSContext', 'cx'),
Argument("Box<%s>" % descriptor.concreteType, 'object', mutable=True)]
- retval = 'Temporary<%s>' % descriptor.concreteType
+ retval = 'Root<%s>' % descriptor.concreteType
CGAbstractMethod.__init__(self, descriptor, 'Wrap', retval, args, pub=True)
def definition_body(self):
if not self.descriptor.isGlobal():
return CGGeneric("""\
+let _ar = JSAutoRequest::new(cx);
let scope = scope.reflector().get_jsobject();
-assert!(!scope.is_null());
-assert!(((*JS_GetClass(scope)).flags & JSCLASS_IS_GLOBAL) != 0);
+assert!(!scope.get().is_null());
+assert!(((*JS_GetClass(scope.get())).flags & JSCLASS_IS_GLOBAL) != 0);
-let proto = with_compartment(cx, scope, || GetProtoObject(cx, scope, scope));
-assert!(!proto.is_null());
+let mut proto = RootedObject::new(cx, ptr::null_mut());
+{
+ let _ac = JSAutoCompartment::new(cx, scope.get());
+ GetProtoObject(cx, scope, scope, proto.handle_mut())
+}
+assert!(!proto.ptr.is_null());
%s
-raw.reflector().set_jsobject(obj);
+(*raw).init_reflector(obj.ptr);
-Temporary::from_unrooted(raw)""" % CreateBindingJSObject(self.descriptor, "scope"))
+Root::from_ref(&*raw)""" % CreateBindingJSObject(self.descriptor, "scope"))
else:
return CGGeneric("""\
+let _ar = JSAutoRequest::new(cx);
%s
-with_compartment(cx, obj, || {
- let proto = GetProtoObject(cx, obj, obj);
- JS_SetPrototype(cx, obj, proto);
- raw.reflector().set_jsobject(obj);
+let _ac = JSAutoCompartment::new(cx, obj.ptr);
+let mut proto = RootedObject::new(cx, ptr::null_mut());
+GetProtoObject(cx, obj.handle(), obj.handle(), proto.handle_mut());
+JS_SetPrototype(cx, obj.handle(), proto.handle());
+
+(*raw).init_reflector(obj.ptr);
- RegisterBindings::Register(cx, obj);
-});
+let ret = Root::from_ref(&*raw);
-Temporary::from_unrooted(raw)""" % CreateBindingJSObject(self.descriptor))
+RegisterBindings::Register(cx, obj.handle());
+
+ret""" % CreateBindingJSObject(self.descriptor))
class CGIDLInterface(CGThing):
@@ -2083,21 +2238,23 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
properties should be a PropertyArrays instance.
"""
def __init__(self, descriptor, properties):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'global'),
- Argument('*mut JSObject', 'receiver')]
- CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', '*mut JSObject', args)
+ args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
+ Argument('HandleObject', 'receiver'),
+ Argument('MutableHandleObject', 'rval')]
+ CGAbstractMethod.__init__(self, descriptor, 'CreateInterfaceObjects', 'void', args)
self.properties = properties
def definition_body(self):
protoChain = self.descriptor.prototypeChain
if len(protoChain) == 1:
- getParentProto = "JS_GetObjectPrototype(cx, global)"
+ getParentProto = "parent_proto.ptr = JS_GetObjectPrototype(cx, global)"
else:
parentProtoName = self.descriptor.prototypeChain[-2]
- getParentProto = ("%s::GetProtoObject(cx, global, receiver)" %
+ getParentProto = ("%s::GetProtoObject(cx, global, receiver, parent_proto.handle_mut())" %
toBindingNamespace(parentProtoName))
- getParentProto = ("let parent_proto: *mut JSObject = %s;\n"
- "assert!(!parent_proto.is_null());\n") % getParentProto
+ getParentProto = ("let mut parent_proto = RootedObject::new(cx, ptr::null_mut());\n"
+ "%s;\n"
+ "assert!(!parent_proto.ptr.is_null());\n") % getParentProto
if self.descriptor.interface.isCallback():
protoClass = "None"
@@ -2127,10 +2284,10 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
constructor = 'None'
call = """\
-return do_create_interface_objects(cx, global, receiver, parent_proto,
- %s, %s,
- %s,
- &sNativeProperties);""" % (protoClass, constructor, domClass)
+do_create_interface_objects(cx, receiver, parent_proto.handle(),
+ %s, %s,
+ %s,
+ &sNativeProperties, rval);""" % (protoClass, constructor, domClass)
return CGList([
CGGeneric(getParentProto),
@@ -2143,10 +2300,11 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
constructor object).
"""
def __init__(self, descriptor, name, idPrefix="", pub=False):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'global'),
- Argument('*mut JSObject', 'receiver')]
+ args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'global'),
+ Argument('HandleObject', 'receiver'),
+ Argument('MutableHandleObject', 'rval')]
CGAbstractMethod.__init__(self, descriptor, name,
- '*mut JSObject', args, pub=pub)
+ 'void', args, pub=pub)
self.id = idPrefix + "ID::" + self.descriptor.name
def definition_body(self):
return CGGeneric("""
@@ -2157,19 +2315,22 @@ class CGGetPerInterfaceObject(CGAbstractMethod):
wrapper and global is the sandbox's global.
*/
-assert!(((*JS_GetClass(global)).flags & JSCLASS_DOM_GLOBAL) != 0);
+assert!(((*JS_GetClass(global.get())).flags & JSCLASS_DOM_GLOBAL) != 0);
/* Check to see whether the interface objects are already installed */
-let proto_or_iface_array = get_proto_or_iface_array(global);
-let cached_object: *mut JSObject = (*proto_or_iface_array)[%s as usize];
-if cached_object.is_null() {
- let tmp: *mut JSObject = CreateInterfaceObjects(cx, global, receiver);
- assert!(!tmp.is_null());
- (*proto_or_iface_array)[%s as usize] = tmp;
- tmp
-} else {
- cached_object
-}""" % (self.id, self.id))
+let proto_or_iface_array = get_proto_or_iface_array(global.get());
+rval.set((*proto_or_iface_array)[%s as usize]);
+if !rval.get().is_null() {
+ return;
+}
+
+CreateInterfaceObjects(cx, global, receiver, rval);
+assert!(!rval.get().is_null());
+(*proto_or_iface_array)[%s as usize] = rval.get();
+if <*mut JSObject>::needs_post_barrier(rval.get()) {
+ <*mut JSObject>::post_barrier((*proto_or_iface_array).as_mut_ptr().offset(%s as isize))
+}
+""" % (self.id, self.id, self.id))
class CGGetProtoObjectMethod(CGGetPerInterfaceObject):
"""
@@ -2224,40 +2385,39 @@ class CGDefineProxyHandler(CGAbstractMethod):
body = """\
let traps = ProxyTraps {
- getPropertyDescriptor: Some(get_property_descriptor as unsafe extern "C" fn(*mut JSContext, *mut JSObject, jsid, bool, *mut JSPropertyDescriptor) -> bool),
- getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor as unsafe extern "C" fn(*mut JSContext, *mut JSObject, jsid, bool, *mut JSPropertyDescriptor) -> bool),
- defineProperty: Some(%s as unsafe extern "C" fn(*mut JSContext, *mut JSObject, jsid, *mut JSPropertyDescriptor) -> bool),
- getOwnPropertyNames: Some(proxyhandler::get_own_property_names as unsafe extern "C" fn(*mut JSContext, *mut JSObject, *mut AutoIdVector) -> bool),
- delete_: Some(%s as unsafe extern "C" fn(*mut JSContext, *mut JSObject, jsid, *mut bool) -> bool),
- enumerate: Some(proxyhandler::enumerate as unsafe extern "C" fn(*mut JSContext, *mut JSObject, *mut AutoIdVector) -> bool),
-
+ enter: None,
+ getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
+ defineProperty: Some(%s),
+ ownPropertyKeys: Some(proxyhandler::own_property_keys),
+ delete_: Some(%s),
+ enumerate: None,
+ preventExtensions: Some(proxyhandler::prevent_extensions),
+ isExtensible: Some(proxyhandler::is_extensible),
has: None,
- hasOwn: Some(hasOwn as unsafe extern "C" fn(*mut JSContext, *mut JSObject, jsid, *mut bool) -> bool),
- get: Some(get as unsafe extern "C" fn(*mut JSContext, *mut JSObject, *mut JSObject, jsid, *mut JSVal) -> bool),
+ get: Some(get),
set: None,
- keys: None,
- iterate: None,
-
call: None,
construct: None,
- nativeCall: ptr::null(),
+ getPropertyDescriptor: Some(get_property_descriptor),
+ hasOwn: Some(hasOwn),
+ getOwnEnumerablePropertyKeys: None,
+ nativeCall: None,
hasInstance: None,
- typeOf: None,
objectClassIs: None,
- obj_toString: Some(obj_toString as unsafe extern "C" fn(*mut JSContext, *mut JSObject) -> *mut js::jsapi::JSString),
+ className: Some(className),
fun_toString: None,
- //regexp_toShared: ptr::null(),
+ boxedValue_unbox: None,
defaultValue: None,
- iteratorNext: None,
- finalize: Some(%s as unsafe extern "C" fn(*mut JSFreeOp, *mut JSObject)),
- getElementIfPresent: None,
- getPrototypeOf: None,
- trace: Some(%s as unsafe extern "C" fn(*mut JSTracer, *mut JSObject))
+ trace: Some(%s),
+ finalize: Some(%s),
+ objectMoved: None,
+ isCallable: None,
+ isConstructor: None,
};
CreateProxyHandler(&traps, &Class as *const _ as *const _)\
-""" % (customDefineProperty, customDelete, FINALIZE_HOOK_NAME,
- TRACE_HOOK_NAME)
+""" % (customDefineProperty, customDelete, TRACE_HOOK_NAME,
+ FINALIZE_HOOK_NAME)
return CGGeneric(body)
@@ -2270,7 +2430,7 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
assert descriptor.interface.hasInterfaceObject()
args = [
Argument('*mut JSContext', 'cx'),
- Argument('*mut JSObject', 'global'),
+ Argument('HandleObject', 'global'),
]
CGAbstractMethod.__init__(self, descriptor, 'DefineDOMInterface', 'void', args, pub=True)
@@ -2279,10 +2439,17 @@ class CGDefineDOMInterfaceMethod(CGAbstractMethod):
def definition_body(self):
if self.descriptor.interface.isCallback():
- code = "CreateInterfaceObjects(cx, global, global);"
+ code = """\
+let mut obj = RootedObject::new(cx, ptr::null_mut());
+CreateInterfaceObjects(cx, global, global, obj.handle_mut());
+"""
else:
- code = "assert!(!GetProtoObject(cx, global, global).is_null());"
- return CGGeneric("assert!(!global.is_null());\n" + code)
+ code = """\
+let mut proto = RootedObject::new(cx, ptr::null_mut());
+GetProtoObject(cx, global, global, proto.handle_mut());
+assert!(!proto.ptr.is_null());
+"""
+ return CGGeneric("assert!(!global.get().is_null());\n" + code)
def needCx(returnType, arguments, considerTypes):
return (considerTypes and
@@ -2329,7 +2496,7 @@ class CGCallGenerator(CGThing):
if static:
call = CGWrapper(call, pre="%s::" % descriptorProvider.interface.identifier.name)
else:
- call = CGWrapper(call, pre="%s.r()." % object)
+ call = CGWrapper(call, pre="%s." % object)
call = CGList([call, CGWrapper(args, pre="(", post=")")])
self.cgRoot.append(CGList([
@@ -2344,8 +2511,7 @@ class CGCallGenerator(CGThing):
if static:
glob = ""
else:
- glob = " let global = global_object_for_js_object(this.r().reflector().get_jsobject());\n"\
- " let global = global.root();\n"
+ glob = " let global = global_object_for_js_object(this.reflector().get_jsobject().get());\n"
self.cgRoot.append(CGGeneric(
"let result = match result {\n"
@@ -2357,9 +2523,6 @@ class CGCallGenerator(CGThing):
" },\n"
"};" % (glob, errorResult)))
- if typeRetValNeedsRooting(returnType):
- self.cgRoot.append(CGGeneric("let result = result.root();"))
-
def define(self):
return self.cgRoot.define()
@@ -2403,22 +2566,15 @@ class CGPerSignatureCall(CGThing):
self.argsPre = argsPre
self.arguments = arguments
self.argCount = len(arguments)
- if self.argCount > argConversionStartsAt:
- # Insert our argv in there
- cgThings = [CGGeneric(self.getArgvDecl())]
- else:
- cgThings = []
- cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgv(),
+ cgThings = []
+ cgThings.extend([CGArgumentConverter(arguments[i], i, self.getArgs(),
self.getArgc(), self.descriptor,
invalidEnumValueFatal=not setter) for
i in range(argConversionStartsAt, self.argCount)])
errorResult = None
if self.isFallible():
- if nativeMethodName == "NamedSetter":
- errorResult = " false"
- else:
- errorResult = " false as JSBool"
+ errorResult = " JSFalse"
cgThings.append(CGCallGenerator(
errorResult,
@@ -2427,10 +2583,8 @@ class CGPerSignatureCall(CGThing):
static))
self.cgRoot = CGList(cgThings, "\n")
- def getArgv(self):
- return "argv" if self.argCount > 0 else ""
- def getArgvDecl(self):
- return "\nlet argv = JS_ARGV(cx, vp);\n"
+ def getArgs(self):
+ return "args" if self.argCount > 0 else ""
def getArgc(self):
return "argc"
def getArguments(self):
@@ -2445,7 +2599,7 @@ class CGPerSignatureCall(CGThing):
return not 'infallible' in self.extendedAttributes
def wrap_return_value(self):
- return wrapForType('*vp')
+ return wrapForType('args.rval()')
def define(self):
return (self.cgRoot.define() + "\n" + self.wrap_return_value())
@@ -2551,7 +2705,7 @@ 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, "u8", args)
if unwrapFailureCode is None:
self.unwrapFailureCode = (
@@ -2568,14 +2722,20 @@ class CGAbstractBindingMethod(CGAbstractExternMethod):
# consumption by FailureFatalCastableObjectUnwrapper.
unwrapThis = str(CastableObjectUnwrapper(
FakeCastableDescriptor(self.descriptor),
- "obj", self.unwrapFailureCode))
+ "obj.handle()", self.unwrapFailureCode, "object"))
unwrapThis = CGGeneric(
- "let obj: *mut JSObject = JS_THIS_OBJECT(cx, vp as *mut JSVal);\n"
- "if obj.is_null() {\n"
- " return false as JSBool;\n"
+ "let args = CallArgs::from_vp(vp, argc);\n"
+ "let thisobj = args.thisv();\n"
+ "if !thisobj.get().is_null_or_undefined() && !thisobj.get().is_object() {\n"
+ " return JSFalse;\n"
"}\n"
+ "let obj = if thisobj.get().is_object() {\n"
+ " RootedObject::new(cx, thisobj.get().to_object())\n"
+ "} else {\n"
+ " RootedObject::new(cx, GetGlobalForObjectCrossCompartment(JS_CALLEE(cx, vp).to_object_or_null()))\n"
+ "};\n"
"\n"
- "let this: Unrooted<%s> = %s;\n" % (self.descriptor.concreteType, unwrapThis))
+ "let this: Root<%s> = %s;\n" % (self.descriptor.concreteType, unwrapThis))
return CGList([ unwrapThis, self.generate_code() ], "\n")
def generate_code(self):
@@ -2596,12 +2756,11 @@ class CGAbstractStaticBindingMethod(CGAbstractMethod):
Argument('libc::c_uint', 'argc'),
Argument('*mut JSVal', 'vp'),
]
- CGAbstractMethod.__init__(self, descriptor, name, "JSBool", args, extern=True)
+ CGAbstractMethod.__init__(self, descriptor, name, "u8", args, extern=True)
def definition_body(self):
preamble = CGGeneric("""\
let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object());
-let global = global.root();
""")
return CGList([preamble, self.generate_code()])
@@ -2621,7 +2780,7 @@ class CGGenericMethod(CGAbstractBindingMethod):
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);")
+ "return CallJitMethodOp(_info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp);")
class CGSpecializedMethod(CGAbstractExternMethod):
"""
@@ -2631,18 +2790,19 @@ class CGSpecializedMethod(CGAbstractExternMethod):
def __init__(self, descriptor, method):
self.method = method
name = method.identifier.name
- args = [Argument('*mut JSContext', 'cx'), Argument('JSHandleObject', '_obj'),
+ args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_obj'),
Argument('*const %s' % descriptor.concreteType, 'this'),
- Argument('libc::c_uint', 'argc'), Argument('*mut JSVal', 'vp')]
- CGAbstractExternMethod.__init__(self, descriptor, name, 'JSBool', args)
+ Argument('*const JSJitMethodCallArgs', 'args')]
+ CGAbstractExternMethod.__init__(self, descriptor, name, 'u8', args)
def definition_body(self):
nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
self.method)
return CGWrapper(CGMethodCall([], nativeName, self.method.isStatic(),
self.descriptor, self.method),
- pre="let this = Unrooted::from_raw(this);\n"
- "let this = this.root();\n")
+ pre="let this = &*this;\n"
+ "let args = &*args;\n"
+ "let argc = args.argc_;\n")
@staticmethod
def makeNativeName(descriptor, method):
@@ -2661,14 +2821,16 @@ class CGStaticMethod(CGAbstractStaticBindingMethod):
def generate_code(self):
nativeName = CGSpecializedMethod.makeNativeName(self.descriptor,
self.method)
- return CGMethodCall(["global.r()"], nativeName, True, self.descriptor, self.method)
+ setupArgs = CGGeneric("let mut args = CallArgs::from_vp(vp, argc);\n")
+ call = CGMethodCall(["global.r()"], nativeName, True, self.descriptor, self.method)
+ return CGList([setupArgs, call])
class CGGenericGetter(CGAbstractBindingMethod):
"""
A class for generating the C++ code for an IDL attribute getter.
"""
def __init__(self, descriptor, lenientThis=False):
- args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', '_argc'),
+ args = [Argument('*mut JSContext', 'cx'), Argument('libc::c_uint', 'argc'),
Argument('*mut JSVal', 'vp')]
if lenientThis:
name = "genericLenientGetter"
@@ -2685,7 +2847,7 @@ class CGGenericGetter(CGAbstractBindingMethod):
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);")
+ "return CallJitGetterOp(info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp);")
class CGSpecializedGetter(CGAbstractExternMethod):
"""
@@ -2696,10 +2858,10 @@ class CGSpecializedGetter(CGAbstractExternMethod):
self.attr = attr
name = 'get_' + attr.identifier.name
args = [ Argument('*mut JSContext', 'cx'),
- Argument('JSHandleObject', '_obj'),
+ Argument('HandleObject', '_obj'),
Argument('*const %s' % descriptor.concreteType, 'this'),
- Argument('*mut JSVal', 'vp') ]
- CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
+ Argument('JSJitGetterCallArgs', 'args') ]
+ CGAbstractExternMethod.__init__(self, descriptor, name, "u8", args)
def definition_body(self):
nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
@@ -2707,8 +2869,7 @@ class CGSpecializedGetter(CGAbstractExternMethod):
return CGWrapper(CGGetterCall([], self.attr.type, nativeName,
self.descriptor, self.attr),
- pre="let this = Unrooted::from_raw(this);\n"
- "let this = this.root();\n")
+ pre="let this = &*this;\n")
@staticmethod
def makeNativeName(descriptor, attr):
@@ -2734,8 +2895,10 @@ class CGStaticGetter(CGAbstractStaticBindingMethod):
def generate_code(self):
nativeName = CGSpecializedGetter.makeNativeName(self.descriptor,
self.attr)
- return CGGetterCall(["global.r()"], self.attr.type, nativeName, self.descriptor,
+ setupArgs = CGGeneric("let mut args = CallArgs::from_vp(vp, argc);\n")
+ call = CGGetterCall(["global.r()"], self.attr.type, nativeName, self.descriptor,
self.attr)
+ return CGList([setupArgs, call])
class CGGenericSetter(CGAbstractBindingMethod):
@@ -2758,10 +2921,8 @@ class CGGenericSetter(CGAbstractBindingMethod):
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"
+ "if CallJitSetterOp(info, cx, obj.handle(), this.r() as *const _ as *const libc::c_void as *mut libc::c_void, argc, vp) == 0 {\n"
" return 0;\n"
"}\n"
"*vp = UndefinedValue();\n"
@@ -2776,18 +2937,17 @@ class CGSpecializedSetter(CGAbstractExternMethod):
self.attr = attr
name = 'set_' + attr.identifier.name
args = [ Argument('*mut JSContext', 'cx'),
- Argument('JSHandleObject', 'obj'),
+ Argument('HandleObject', 'obj'),
Argument('*const %s' % descriptor.concreteType, 'this'),
- Argument('*mut JSVal', 'argv')]
- CGAbstractExternMethod.__init__(self, descriptor, name, "JSBool", args)
+ Argument('JSJitSetterCallArgs', 'args')]
+ CGAbstractExternMethod.__init__(self, descriptor, name, "u8", args)
def definition_body(self):
nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
self.attr)
return CGWrapper(CGSetterCall([], self.attr.type, nativeName,
self.descriptor, self.attr),
- pre="let this = Unrooted::from_raw(this);\n"
- "let this = this.root();\n")
+ pre="let this = &*this;\n")
@staticmethod
def makeNativeName(descriptor, attr):
@@ -2808,7 +2968,7 @@ class CGStaticSetter(CGAbstractStaticBindingMethod):
nativeName = CGSpecializedSetter.makeNativeName(self.descriptor,
self.attr)
checkForArg = CGGeneric(
- "let argv = JS_ARGV(cx, vp);\n"
+ "let args = CallArgs::from_vp(vp, argc);\n"
"if (argc == 0) {\n"
" throw_type_error(cx, \"Not enough arguments to %s setter.\");\n"
" return 0;\n"
@@ -2831,17 +2991,17 @@ class CGSpecializedForwardingSetter(CGSpecializedSetter):
assert all(ord(c) < 128 for c in attrName)
assert all(ord(c) < 128 for c in forwardToAttrName)
return CGGeneric("""\
-let mut v = UndefinedValue();
-if JS_GetProperty(cx, *obj.unnamed_field1, b"%s".as_ptr() as *const i8, &mut v) == 0 {
- return 0;
+let mut v = RootedValue::new(cx, UndefinedValue());
+if JS_GetProperty(cx, obj, %s as *const u8 as *const i8, v.handle_mut()) == 0 {
+ return JSFalse;
}
-if !v.is_object() {
+if !v.ptr.is_object() {
throw_type_error(cx, "Value.%s is not an object.");
- return 0;
+ return JSFalse;
}
-let target_obj = v.to_object();
-JS_SetProperty(cx, target_obj, b"%s".as_ptr() as *const i8, argv.offset(0))
-""" % (attrName, attrName, forwardToAttrName))
+let target_obj = RootedObject::new(cx, v.ptr.to_object());
+JS_SetProperty(cx, target_obj.handle(), %s as *const u8 as *const i8, args.get(0))
+""" % (str_to_const_array(attrName), attrName, str_to_const_array(forwardToAttrName)))
class CGMemberJITInfo(CGThing):
"""
@@ -2852,52 +3012,253 @@ class CGMemberJITInfo(CGThing):
self.member = member
self.descriptor = descriptor
- def defineJitInfo(self, infoName, opName, infallible):
- protoID = "PrototypeList::ID::%s as u32" % self.descriptor.name
- depth = self.descriptor.interface.inheritanceDepth()
- failstr = "true" if infallible else "false"
- return ("const %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))
+ def defineJitInfo(self, infoName, opName, opType, infallible, movable,
+ aliasSet, alwaysInSlot, lazilyInSlot, slotIndex,
+ returnTypes, args):
+ """
+ aliasSet is a JSJitInfo::AliasSet value, without the "JSJitInfo::" bit.
+
+ args is None if we don't want to output argTypes for some
+ reason (e.g. we have overloads or we're not a method) and
+ otherwise an iterable of the arguments for this method.
+ """
+ assert(not movable or aliasSet != "AliasEverything") # Can't move write-aliasing things
+ assert(not alwaysInSlot or movable) # Things always in slots had better be movable
+
+ def jitInfoInitializer(isTypedMethod):
+ initializer = fill(
+ """
+ JSJitInfo {
+ _bindgen_data_1_: ${opName} as *const ::libc::c_void,
+ protoID: PrototypeList::ID::${name} as u16,
+ depth: ${depth},
+ _bitfield_1: ((JSJitInfo_OpType::${opType} as u32) << 0) |
+ ((JSJitInfo_AliasSet::${aliasSet} as u32) << 4) |
+ ((JSValueType::${returnType} as u32) << 8) |
+ ((${isInfallible} as u32) << 16) |
+ ((${isMovable} as u32) << 17) |
+ ((${isAlwaysInSlot} as u32) << 18) |
+ ((${isLazilyCachedInSlot} as u32) << 19) |
+ ((${isTypedMethod} as u32) << 20) |
+ ((${slotIndex} as u32) << 21)
+ }
+ """,
+ opName=opName,
+ name=self.descriptor.name,
+ depth=self.descriptor.interface.inheritanceDepth(),
+ opType=opType,
+ aliasSet=aliasSet,
+ returnType=reduce(CGMemberJITInfo.getSingleReturnType, returnTypes,
+ ""),
+ isInfallible=toStringBool(infallible),
+ isMovable=toStringBool(movable),
+ isAlwaysInSlot=toStringBool(alwaysInSlot),
+ isLazilyCachedInSlot=toStringBool(lazilyInSlot),
+ isTypedMethod=toStringBool(isTypedMethod),
+ slotIndex=slotIndex)
+ return initializer.rstrip()
+
+ return ("\n"
+ "const %s: JSJitInfo = %s;\n"
+ % (infoName, jitInfoInitializer(False)))
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)
- if not self.member.readonly or self.member.getExtendedAttribute("PutForwards"):
+
+ movable = self.mayBeMovable() and getterinfal
+ aliasSet = self.aliasSet()
+
+ isAlwaysInSlot = self.member.getExtendedAttribute("StoreInSlot")
+ if self.member.slotIndex is not None:
+ assert isAlwaysInSlot or self.member.getExtendedAttribute("Cached")
+ isLazilyCachedInSlot = not isAlwaysInSlot
+ slotIndex = memberReservedSlot(self.member)
+ # We'll statically assert that this is not too big in
+ # CGUpdateMemberSlotsMethod, in the case when
+ # isAlwaysInSlot is true.
+ else:
+ isLazilyCachedInSlot = False
+ slotIndex = "0"
+
+ result = self.defineJitInfo(getterinfo, getter, "Getter",
+ getterinfal, movable, aliasSet,
+ isAlwaysInSlot, isLazilyCachedInSlot,
+ slotIndex,
+ [self.member.type], None)
+ if (not self.member.readonly or
+ self.member.getExtendedAttribute("PutForwards")):
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 += "\n" + self.defineJitInfo(setterinfo, setter, False)
+ result += self.defineJitInfo(setterinfo, setter, "Setter",
+ False, False, "AliasEverything",
+ False, False, "0",
+ [BuiltinTypes[IDLBuiltinType.Types.void]],
+ None)
return result
if self.member.isMethod():
methodinfo = ("%s_methodinfo" % self.member.identifier.name)
- # Actually a JSJitMethodOp, but JSJitPropertyOp by struct definition.
method = ("%s" % self.member.identifier.name)
# Methods are infallible if they are infallible, have no arguments
# to unwrap, and have a return type that's infallible to wrap up for
# return.
- methodInfal = False
sigs = self.member.signatures()
- if len(sigs) == 1:
+ if len(sigs) != 1:
# Don't handle overloading. If there's more than one signature,
# one of them must take arguments.
+ methodInfal = False
+ args = None
+ movable = False
+ else:
sig = sigs[0]
- if len(sig[1]) == 0:
- # No arguments and infallible return boxing
- methodInfal = True
+ # For methods that affect nothing, it's OK to set movable to our
+ # notion of infallible on the C++ side, without considering
+ # argument conversions, since argument conversions that can
+ # reliably throw would be effectful anyway and the jit doesn't
+ # move effectful things.
+ hasInfallibleImpl = "infallible" in self.descriptor.getExtendedAttributes(self.member)
+ movable = self.mayBeMovable() and hasInfallibleImpl
+ # XXXbz can we move the smarts about fallibility due to arg
+ # conversions into the JIT, using our new args stuff?
+ if (len(sig[1]) != 0):
+ # We have arguments or our return-value boxing can fail
+ methodInfal = False
+ else:
+ methodInfal = hasInfallibleImpl
+ # For now, only bother to output args if we're side-effect-free.
+ if self.member.affects == "Nothing":
+ args = sig[1]
+ else:
+ args = None
- result = self.defineJitInfo(methodinfo, method, methodInfal)
+ aliasSet = self.aliasSet()
+ result = self.defineJitInfo(methodinfo, method, "Method",
+ methodInfal, movable, aliasSet,
+ False, False, "0",
+ [s[0] for s in sigs], args)
return result
raise TypeError("Illegal member type to CGPropertyJITInfo")
+ def mayBeMovable(self):
+ """
+ Returns whether this attribute or method may be movable, just
+ based on Affects/DependsOn annotations.
+ """
+ affects = self.member.affects
+ dependsOn = self.member.dependsOn
+ assert affects in IDLInterfaceMember.AffectsValues
+ assert dependsOn in IDLInterfaceMember.DependsOnValues
+ # Things that are DependsOn=DeviceState are not movable, because we
+ # don't want them coalesced with each other or loop-hoisted, since
+ # their return value can change even if nothing is going on from our
+ # point of view.
+ return (affects == "Nothing" and
+ (dependsOn != "Everything" and dependsOn != "DeviceState"))
+
+ def aliasSet(self):
+ """Returns the alias set to store in the jitinfo. This may not be the
+ effective alias set the JIT uses, depending on whether we have enough
+ information about our args to allow the JIT to prove that effectful
+ argument conversions won't happen.
+
+ """
+ dependsOn = self.member.dependsOn
+ assert dependsOn in IDLInterfaceMember.DependsOnValues
+
+ if dependsOn == "Nothing" or dependsOn == "DeviceState":
+ assert self.member.affects == "Nothing"
+ return "AliasNone"
+
+ if dependsOn == "DOMState":
+ assert self.member.affects == "Nothing"
+ return "AliasDOMSets"
+
+ return "AliasEverything"
+
+ @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.isMozMap():
+ 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.unrestricted_float, IDLType.Tags.float,
+ IDLType.Tags.unrestricted_double, 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",
@@ -2933,7 +3294,7 @@ pub enum %s {
inner = """\
use dom::bindings::conversions::ToJSValConvertible;
-use js::jsapi::JSContext;
+use js::jsapi::{JSContext, MutableHandleValue};
use js::jsval::JSVal;
pub const strings: &'static [&'static str] = &[
@@ -2941,8 +3302,8 @@ pub const strings: &'static [&'static str] = &[
];
impl ToJSValConvertible for super::%s {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- strings[*self as usize].to_jsval(cx)
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ strings[*self as usize].to_jsval(cx, rval);
}
}
""" % (",\n ".join(['"%s"' % val for val in enum.values()]), enum.identifier.name)
@@ -3047,7 +3408,7 @@ class CGUnionStruct(CGThing):
" e%s(%s)," % (v["name"], v["typeName"]) for v in templateVars
]
enumConversions = [
- " %s::e%s(ref inner) => inner.to_jsval(cx)," % (self.type, v["name"]) for v in templateVars
+ " %s::e%s(ref inner) => inner.to_jsval(cx, rval)," % (self.type, v["name"]) for v in templateVars
]
# XXXManishearth The following should be #[must_root],
# however we currently allow it till #2661 is fixed
@@ -3058,7 +3419,7 @@ pub enum %s {
}
impl ToJSValConvertible for %s {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
match *self {
%s
}
@@ -3147,7 +3508,7 @@ class CGUnionConversionStruct(CGThing):
if hasObjectTypes:
assert interfaceObject
templateBody = CGList([interfaceObject], "\n")
- conversions.append(CGIfWrapper(templateBody, "value.is_object()"))
+ conversions.append(CGIfWrapper(templateBody, "value.get().is_object()"))
otherMemberTypes = [
t for t in memberTypes if t.isPrimitive() or t.isString() or t.isEnum()
@@ -3173,7 +3534,7 @@ class CGUnionConversionStruct(CGThing):
"Err(())" % ", ".join(names)))
method = CGWrapper(
CGIndenter(CGList(conversions, "\n\n")),
- pre="fn from_jsval(cx: *mut JSContext, value: JSVal, _option: ()) -> Result<%s, ()> {\n" % self.type,
+ pre="fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ()) -> Result<%s, ()> {\n" % self.type,
post="\n}")
return CGWrapper(
CGIndenter(CGList([
@@ -3190,7 +3551,7 @@ class CGUnionConversionStruct(CGThing):
return CGWrapper(
CGIndenter(jsConversion, 4),
- pre="fn TryConvertTo%s(cx: *mut JSContext, value: JSVal) -> %s {\n" % (t.name, returnType),
+ pre="fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n" % (t.name, returnType),
post="\n}")
def define(self):
@@ -3236,6 +3597,7 @@ class ClassMethod(ClassItem):
override indicates whether to flag the method as MOZ_OVERRIDE
"""
assert not override or virtual
+ assert not (override and static)
self.returnType = returnType
self.args = args
self.inline = False
@@ -3378,9 +3740,14 @@ class ClassConstructor(ClassItem):
def getBody(self, cgClass):
initializers = [" parent: %s" % str(self.baseConstructors[0])]
return (self.body + (
- "%s {\n"
+ "let mut ret = Rc::new(%s {\n"
"%s\n"
- "}") % (cgClass.name, '\n'.join(initializers)))
+ "});\n"
+ "match rc::get_mut(&mut ret) {\n"
+ " Some(ref mut callback) => callback.parent.init(%s),\n"
+ " None => unreachable!(),\n"
+ "};\n"
+ "ret") % (cgClass.name, '\n'.join(initializers), self.args[0].name))
def declare(self, cgClass):
args = ', '.join([a.declare() for a in self.args])
@@ -3391,7 +3758,7 @@ class ClassConstructor(ClassItem):
body = ' {\n' + body + '}'
return string.Template("""\
-pub fn ${decorators}new(${args}) -> ${className}${body}
+pub fn ${decorators}new(${args}) -> Rc<${className}>${body}
""").substitute({ 'decorators': self.getDecorators(True),
'className': cgClass.getNameString(),
'args': args,
@@ -3692,17 +4059,18 @@ class CGProxySpecialOperation(CGPerSignatureCall):
argument = arguments[1]
info = getJSToNativeConversionInfo(
argument.type, descriptor, treatNullAs=argument.treatNullAs,
- exceptionCode="return false;")
+ exceptionCode="return JSFalse;")
template = info.template
declType = info.declType
needsRooting = info.needsRooting
templateValues = {
- "val": "(*desc).value",
+ "val": "value.handle()",
}
self.cgRoot.prepend(instantiateJSToNativeConversionTemplate(
template, templateValues, declType, argument.identifier.name,
needsRooting))
+ self.cgRoot.prepend(CGGeneric("let value = RootedValue::new(cx, desc.get().value);"))
elif operation.isGetter():
self.cgRoot.prepend(CGGeneric("let mut found = false;"))
@@ -3777,7 +4145,7 @@ class CGProxyNamedDeleter(CGProxySpecialOperation):
class CGProxyUnwrap(CGAbstractMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSObject', 'obj')]
+ args = [Argument('HandleObject', 'obj')]
CGAbstractMethod.__init__(self, descriptor, "UnwrapProxy", '*const ' + descriptor.concreteType, args, alwaysInline=True)
def definition_body(self):
@@ -3786,103 +4154,78 @@ class CGProxyUnwrap(CGAbstractMethod):
obj = js::UnwrapObject(obj);
}*/
//MOZ_ASSERT(IsProxy(obj));
-let box_ = GetProxyPrivate(obj).to_private() as *const %s;
+let box_ = GetProxyPrivate(*obj.ptr).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('HandleObject', 'proxy'),
+ Argument('HandleId', 'id'),
+ Argument('MutableHandle<JSPropertyDescriptor>', 'desc')]
CGAbstractExternMethod.__init__(self, descriptor, "getOwnPropertyDescriptor",
- "bool", args)
+ "u8", args)
self.descriptor = descriptor
def getBody(self):
indexedGetter = self.descriptor.operations['IndexedGetter']
indexedSetter = self.descriptor.operations['IndexedSetter']
- setOrIndexedGet = ""
+ get = ""
if indexedGetter or indexedSetter:
- setOrIndexedGet += "let index = get_array_index_from_id(cx, id);\n"
+ get = "let index = get_array_index_from_id(cx, id);\n"
if indexedGetter:
readonly = toStringBool(self.descriptor.operations['IndexedSetter'] is None)
- fillDescriptor = "fill_property_descriptor(&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" +
- " let this = Unrooted::from_raw(this);\n" +
- " let this = this.root();\n" +
- CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
- "}\n")
-
- if indexedSetter or self.descriptor.operations['NamedSetter']:
- setOrIndexedGet += "if set {\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 += (" fill_property_descriptor(&mut *desc, proxy, false);\n" +
- " return true;\n" +
- " }\n")
- if self.descriptor.operations['NamedSetter']:
- setOrIndexedGet += " if RUST_JSID_IS_STRING(id) != 0 {\n"
- if not 'NamedCreator' in self.descriptor.operations:
- # FIXME need to check that this is a 'supported property name'
- assert False
- setOrIndexedGet += (" fill_property_descriptor(&mut *desc, proxy, false);\n" +
- " return true;\n" +
- " }\n")
- setOrIndexedGet += "}"
- if indexedGetter:
- setOrIndexedGet += (" else {\n" +
- CGIndenter(CGGeneric(get)).define() +
- "}")
- setOrIndexedGet += "\n\n"
- elif indexedGetter:
- setOrIndexedGet += ("if !set {\n" +
- CGIndenter(CGGeneric(get)).define() +
- "}\n\n")
+ fillDescriptor = "desc.get().value = result_root.ptr;\nfill_property_descriptor(&mut *desc.ptr, *proxy.ptr, %s);\nreturn JSTrue;" % readonly
+ templateValues = {
+ 'jsvalRef': 'result_root.handle_mut()',
+ 'successCode': fillDescriptor,
+ 'pre': 'let mut result_root = RootedValue::new(cx, UndefinedValue());'
+ }
+ get += ("if index.is_some() {\n" +
+ " let index = index.unwrap();\n" +
+ " let this = UnwrapProxy(proxy);\n" +
+ " let this = &*this;\n" +
+ CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
+ "}\n")
namedGetter = self.descriptor.operations['NamedGetter']
if namedGetter:
readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
- fillDescriptor = "fill_property_descriptor(&mut *desc, proxy, %s);\nreturn true;" % readonly
- templateValues = {'jsvalRef': '(*desc).value', 'successCode': fillDescriptor}
+ fillDescriptor = "desc.get().value = result_root.ptr;\nfill_property_descriptor(&mut *desc.ptr, *proxy.ptr, %s);\nreturn JSTrue;" % readonly
+ templateValues = {
+ 'jsvalRef': 'result_root.handle_mut()',
+ 'successCode': fillDescriptor,
+ 'pre': 'let mut result_root = RootedValue::new(cx, UndefinedValue());'
+ }
# 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 && !has_property_on_prototype(cx, proxy, id) {\n" +
+ "if RUST_JSID_IS_STRING(id) != 0 && !has_property_on_prototype(cx, proxy, id) {\n" +
" let name = jsid_to_str(cx, id);\n" +
" let this = UnwrapProxy(proxy);\n" +
- " let this = Unrooted::from_raw(this);\n" +
- " let this = this.root();\n" +
+ " let this = &*this;\n" +
CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() + "\n" +
"}\n")
else:
namedGet = ""
- return setOrIndexedGet + """\
-let expando: *mut JSObject = get_expando_object(proxy);
+ return get + """\
+let expando = RootedObject::new(cx, get_expando_object(proxy));
//if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
-if !expando.is_null() {
- let flags = if set { JSRESOLVE_ASSIGNING } else { 0 } | JSRESOLVE_QUALIFIED;
- if JS_GetPropertyDescriptorById(cx, expando, id, flags, desc) == 0 {
- return false;
+if !expando.ptr.is_null() {
+ if JS_GetPropertyDescriptorById(cx, expando.handle(), id, desc) == 0 {
+ return JSFalse;
}
- if !(*desc).obj.is_null() {
+ if !desc.get().obj.is_null() {
// Pretend the property lives on the wrapper.
- (*desc).obj = proxy;
- return true;
+ desc.get().obj = *proxy.ptr;
+ return JSTrue;
}
}
""" + namedGet + """\
-(*desc).obj = ptr::null_mut();
-return true;"""
+desc.get().obj = ptr::null_mut();
+return JSTrue;"""
def definition_body(self):
return CGGeneric(self.getBody())
@@ -3890,10 +4233,11 @@ return true;"""
# TODO(Issue 5876)
class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'),
- Argument('jsid', 'id'),
- Argument('*mut JSPropertyDescriptor', 'desc')]
- CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "bool", args)
+ args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
+ Argument('HandleId', 'id'),
+ Argument('Handle<JSPropertyDescriptor>', 'desc'),
+ Argument('*mut ObjectOpResult', 'opresult')]
+ CGAbstractExternMethod.__init__(self, descriptor, "defineProperty", "u8", args)
self.descriptor = descriptor
def getBody(self):
set = ""
@@ -3906,14 +4250,13 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
"if index.is_some() {\n" +
" let index = index.unwrap();\n" +
" let this = UnwrapProxy(proxy);\n" +
- " let this = Unrooted::from_raw(this);\n" +
- " let this = this.root();\n" +
+ " let this = &*this;\n" +
CGIndenter(CGProxyIndexedSetter(self.descriptor)).define() +
- " return true;\n" +
+ " return JSTrue;\n" +
"}\n")
elif self.descriptor.operations['IndexedGetter']:
set += ("if get_array_index_from_id(cx, id).is_some() {\n" +
- " return false;\n" +
+ " return JSFalse;\n" +
" //return ThrowErrorMessage(cx, MSG_NO_PROPERTY_SETTER, \"%s\");\n" +
"}\n") % self.descriptor.name
@@ -3924,30 +4267,30 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" +
" let name = jsid_to_str(cx, id);\n" +
" let this = UnwrapProxy(proxy);\n" +
- " let this = Unrooted::from_raw(this);\n" +
- " let this = this.root();\n" +
+ " let this = &*this;\n" +
CGIndenter(CGProxyNamedSetter(self.descriptor)).define() +
- " return true;\n" +
+ " (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" +
+ " return JSTrue;\n" +
"} else {\n" +
- " return false;\n" +
+ " return JSFalse;\n" +
"}\n")
else:
- if self.descriptor.operations['NamedGetter']:
- set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" +
- " let name = jsid_to_str(cx, id);\n" +
- " let this = UnwrapProxy(proxy);\n" +
- " let this = Unrooted::from_raw(this);\n" +
- " let this = this.root();\n" +
- CGProxyNamedPresenceChecker(self.descriptor).define() +
- " if (found) {\n" +
- # TODO(Issue 5876)
- " //return js::IsInNonStrictPropertySet(cx)\n" +
- " // ? opresult.succeed()\n" +
- " // : ThrowErrorMessage(cx, MSG_NO_NAMED_SETTER, \"${name}\");\n" +
- " return true;\n" +
- " }\n" +
- "}"
- ) % (self.descriptor.name, self.descriptor.name)
+ set += ("if RUST_JSID_IS_STRING(id) != 0 {\n" +
+ " let name = jsid_to_str(cx, id);\n" +
+ " let this = UnwrapProxy(proxy);\n" +
+ " let this = &*this;\n" +
+ CGIndenter(CGProxyNamedGetter(self.descriptor)).define() +
+ " if (found) {\n"
+ # TODO(Issue 5876)
+ " //return js::IsInNonStrictPropertySet(cx)\n" +
+ " // ? opresult.succeed()\n" +
+ " // : ThrowErrorMessage(cx, MSG_NO_NAMED_SETTER, \"${name}\");\n" +
+ " (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" +
+ " return JSTrue;\n" +
+ " }\n" +
+ " (*opresult).code_ = 0; /* SpecialCodes::OkCode */\n" +
+ " return JSTrue;\n"
+ "}\n") % (self.descriptor.name, self.descriptor.name)
set += "return proxyhandler::define_property(%s);" % ", ".join(a.name for a in self.args)
return set
@@ -3956,10 +4299,10 @@ class CGDOMJSProxyHandler_defineProperty(CGAbstractExternMethod):
class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'),
- Argument('jsid', 'id'),
- Argument('*mut bool', 'bp')]
- CGAbstractExternMethod.__init__(self, descriptor, "delete", "bool", args)
+ args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
+ Argument('HandleId', 'id'),
+ Argument('*mut ObjectOpResult', 'res')]
+ CGAbstractExternMethod.__init__(self, descriptor, "delete", "u8", args)
self.descriptor = descriptor
def getBody(self):
@@ -3967,10 +4310,9 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
if self.descriptor.operations['NamedDeleter']:
set += ("let name = jsid_to_str(cx, id);\n" +
"let this = UnwrapProxy(proxy);\n" +
- "let this = Unrooted::from_raw(this);\n" +
- "let this = this.root();\n" +
+ "let this = &*this;\n" +
"%s") % (CGProxyNamedDeleter(self.descriptor).define())
- set += "return proxyhandler::delete(%s);" % ", ".join(a.name for a in self.args)
+ set += "return proxyhandler::delete(%s) as u8;" % ", ".join(a.name for a in self.args)
return set
def definition_body(self):
@@ -3978,9 +4320,9 @@ class CGDOMJSProxyHandler_delete(CGAbstractExternMethod):
class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', 'proxy'),
- Argument('jsid', 'id'), Argument('*mut bool', 'bp')]
- CGAbstractExternMethod.__init__(self, descriptor, "hasOwn", "bool", args)
+ args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
+ Argument('HandleId', 'id'), Argument('*mut u8', 'bp')]
+ CGAbstractExternMethod.__init__(self, descriptor, "hasOwn", "u8", args)
self.descriptor = descriptor
def getBody(self):
indexedGetter = self.descriptor.operations['IndexedGetter']
@@ -3989,11 +4331,10 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
"if index.is_some() {\n" +
" let index = index.unwrap();\n" +
" let this = UnwrapProxy(proxy);\n" +
- " let this = Unrooted::from_raw(this);\n" +
- " let this = this.root();\n" +
+ " let this = &*this;\n" +
CGIndenter(CGProxyIndexedGetter(self.descriptor)).define() + "\n" +
- " *bp = found;\n" +
- " return true;\n" +
+ " *bp = found as u8;\n" +
+ " return JSTrue;\n" +
"}\n\n")
else:
indexed = ""
@@ -4003,57 +4344,56 @@ class CGDOMJSProxyHandler_hasOwn(CGAbstractExternMethod):
named = ("if RUST_JSID_IS_STRING(id) != 0 && !has_property_on_prototype(cx, proxy, id) {\n" +
" let name = jsid_to_str(cx, id);\n" +
" let this = UnwrapProxy(proxy);\n" +
- " let this = Unrooted::from_raw(this);\n" +
- " let this = this.root();\n" +
+ " let this = &*this;\n" +
CGIndenter(CGProxyNamedGetter(self.descriptor)).define() + "\n" +
- " *bp = found;\n"
- " return true;\n"
+ " *bp = found as u8;\n"
+ " return JSTrue;\n"
"}\n" +
"\n")
else:
named = ""
return indexed + """\
-let expando: *mut JSObject = get_expando_object(proxy);
-if !expando.is_null() {
- let mut b: JSBool = 1;
- let ok = JS_HasPropertyById(cx, expando, id, &mut b) != 0;
- *bp = b != 0;
- if !ok || *bp {
- return ok;
+let expando = RootedObject::new(cx, get_expando_object(proxy));
+if !expando.ptr.is_null() {
+ let mut b: u8 = 1;
+ let ok = JS_HasPropertyById(cx, expando.handle(), id, &mut b) != 0;
+ *bp = (b != 0) as u8;
+ if !ok || *bp != 0 {
+ return ok as u8;
}
}
""" + named + """\
-*bp = false;
-return true;"""
+*bp = JSFalse;
+return JSTrue;"""
def definition_body(self):
return CGGeneric(self.getBody())
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')]
- CGAbstractExternMethod.__init__(self, descriptor, "get", "bool", args)
+ args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', 'proxy'),
+ Argument('HandleObject', '_receiver'), Argument('HandleId', 'id'),
+ Argument('MutableHandleValue', 'vp')]
+ CGAbstractExternMethod.__init__(self, descriptor, "get", "u8", args)
self.descriptor = descriptor
def getBody(self):
getFromExpando = """\
-let expando = get_expando_object(proxy);
-if !expando.is_null() {
+let expando = RootedObject::new(cx, get_expando_object(proxy));
+if !expando.ptr.is_null() {
let mut hasProp = 0;
- if JS_HasPropertyById(cx, expando, id, &mut hasProp) == 0 {
- return false;
+ if JS_HasPropertyById(cx, expando.handle(), id, &mut hasProp) == 0 {
+ return JSFalse;
}
if hasProp != 0 {
- return JS_GetPropertyById(cx, expando, id, vp) != 0;
+ return (JS_GetPropertyById(cx, expando.handle(), id, vp) != 0) as u8;
}
}"""
templateValues = {
- 'jsvalRef': '*vp',
- 'successCode': 'return true;',
+ 'jsvalRef': 'vp',
+ 'successCode': 'return JSTrue;',
}
indexedGetter = self.descriptor.operations['IndexedGetter']
@@ -4062,8 +4402,7 @@ if !expando.is_null() {
"if index.is_some() {\n" +
" let index = index.unwrap();\n" +
" let this = UnwrapProxy(proxy);\n" +
- " let this = Unrooted::from_raw(this);\n" +
- " let this = this.root();\n" +
+ " let this = &*this;\n" +
CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define())
getIndexedOrExpando += """\
// Even if we don't have this index, we don't forward the
@@ -4080,8 +4419,7 @@ if !expando.is_null() {
getNamed = ("if (RUST_JSID_IS_STRING(id) != 0) {\n" +
" let name = jsid_to_str(cx, id);\n" +
" let this = UnwrapProxy(proxy);\n" +
- " let this = Unrooted::from_raw(this);\n" +
- " let this = this.root();\n" +
+ " let this = &*this;\n" +
CGIndenter(CGProxyNamedGetter(self.descriptor, templateValues)).define() +
"}\n")
else:
@@ -4094,26 +4432,26 @@ if !expando.is_null() {
%s
let mut found = false;
if !get_property_on_prototype(cx, proxy, id, &mut found, vp) {
- return false;
+ return JSFalse;
}
if found {
- return true;
+ return JSTrue;
}
%s
-*vp = UndefinedValue();
-return true;""" % (getIndexedOrExpando, getNamed)
+*vp.ptr = UndefinedValue();
+return JSTrue;""" % (getIndexedOrExpando, getNamed)
def definition_body(self):
return CGGeneric(self.getBody())
-class CGDOMJSProxyHandler_obj_toString(CGAbstractExternMethod):
+class CGDOMJSProxyHandler_className(CGAbstractExternMethod):
def __init__(self, descriptor):
- args = [Argument('*mut JSContext', 'cx'), Argument('*mut JSObject', '_proxy')]
- CGAbstractExternMethod.__init__(self, descriptor, "obj_toString", "*mut JSString", args)
+ args = [Argument('*mut JSContext', 'cx'), Argument('HandleObject', '_proxy')]
+ CGAbstractExternMethod.__init__(self, descriptor, "className", "*const i8", args)
self.descriptor = descriptor
def getBody(self):
- return """proxyhandler::object_to_string(cx, "%s")""" % self.descriptor.name
+ return '%s as *const u8 as *const i8' % str_to_const_array(self.descriptor.name)
def definition_body(self):
return CGGeneric(self.getBody())
@@ -4165,7 +4503,8 @@ class CGClassTraceHook(CGAbstractClassHook):
self.traceGlobal = descriptor.isGlobal()
def generate_code(self):
- body = [CGGeneric("(*this).trace(%s);" % self.args[0].name)]
+ body = [CGGeneric("if this.is_null() { return; } // GC during obj creation\n"
+ "(*this).trace(%s);" % self.args[0].name)]
if self.traceGlobal:
body += [CGGeneric("trace_global(trc, obj);")]
return CGList(body, "\n")
@@ -4177,7 +4516,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)
+ 'u8', args)
self._ctor = self.descriptor.interface.ctor()
def define(self):
@@ -4188,7 +4527,7 @@ class CGClassConstructHook(CGAbstractExternMethod):
def definition_body(self):
preamble = CGGeneric("""\
let global = global_object_for_js_object(JS_CALLEE(cx, vp).to_object());
-let global = global.root();
+let args = CallArgs::from_vp(vp, argc);
""")
name = self._ctor.identifier.name
nativeName = MakeNativeName(self.descriptor.binaryNameFor(name))
@@ -4201,7 +4540,7 @@ class CGClassFinalizeHook(CGAbstractClassHook):
A hook for finalize, used to release our native object.
"""
def __init__(self, descriptor):
- args = [Argument('*mut JSFreeOp', '_fop'), Argument('*mut JSObject', 'obj')]
+ args = [Argument('*mut FreeOp', '_fop'), Argument('*mut JSObject', 'obj')]
CGAbstractClassHook.__init__(self, descriptor, FINALIZE_HOOK_NAME,
'void', args)
@@ -4391,7 +4730,7 @@ class CGDescriptor(CGThing):
cgThings.append(CGProxyUnwrap(descriptor))
cgThings.append(CGDOMJSProxyHandlerDOMClass(descriptor))
cgThings.append(CGDOMJSProxyHandler_getOwnPropertyDescriptor(descriptor))
- cgThings.append(CGDOMJSProxyHandler_obj_toString(descriptor))
+ cgThings.append(CGDOMJSProxyHandler_className(descriptor))
cgThings.append(CGDOMJSProxyHandler_get(descriptor))
cgThings.append(CGDOMJSProxyHandler_hasOwn(descriptor))
@@ -4427,7 +4766,7 @@ class CGDescriptor(CGThing):
return self.cgRoot.define()
class CGNonNamespacedEnum(CGThing):
- def __init__(self, enumName, names, values, comment="", deriving=""):
+ def __init__(self, enumName, names, values, comment="", deriving="", repr=""):
if not values:
values = []
@@ -4449,6 +4788,8 @@ class CGNonNamespacedEnum(CGThing):
# Build the enum body.
enumstr = comment + 'pub enum %s {\n%s\n}\n' % (enumName, ',\n'.join(entries))
+ if repr:
+ enumstr = ('#[repr(%s)]\n' % repr) + enumstr
if deriving:
enumstr = ('#[derive(%s)]\n' % deriving) + enumstr
curr = CGGeneric(enumstr)
@@ -4523,13 +4864,13 @@ class CGDictionary(CGThing):
def memberInit(memberInfo):
member, _ = memberInfo
name = self.makeMemberName(member.identifier.name)
- conversion = self.getMemberConversion(memberInfo)
+ conversion = self.getMemberConversion(memberInfo, member.type)
return CGGeneric("%s: %s,\n" % (name, conversion.define()))
def memberInsert(memberInfo):
member, _ = memberInfo
name = self.makeMemberName(member.identifier.name)
- insertion = ("set_dictionary_property(cx, obj, \"%s\", &mut self.%s.to_jsval(cx)).unwrap();" % (name, name))
+ insertion = ("let mut %s = RootedValue::new(cx, UndefinedValue());\nself.%s.to_jsval(cx, %s.handle_mut());\nset_dictionary_property(cx, obj.handle(), \"%s\", %s.handle()).unwrap();" % (name, name, name, name, name))
return CGGeneric("%s\n" % insertion)
memberInits = CGList([memberInit(m) for m in self.memberInfo])
@@ -4537,14 +4878,14 @@ class CGDictionary(CGThing):
return string.Template(
"impl ${selfName} {\n"
- " pub fn empty() -> ${selfName} {\n"
- " ${selfName}::new(ptr::null_mut(), NullValue()).unwrap()\n"
+ " pub fn empty(cx: *mut JSContext) -> ${selfName} {\n"
+ " ${selfName}::new(cx, HandleValue::null()).unwrap()\n"
" }\n"
- " pub fn new(cx: *mut JSContext, val: JSVal) -> Result<${selfName}, ()> {\n"
- " let object = if val.is_null_or_undefined() {\n"
- " ptr::null_mut()\n"
- " } else if val.is_object() {\n"
- " val.to_object()\n"
+ " pub fn new(cx: *mut JSContext, val: HandleValue) -> Result<${selfName}, ()> {\n"
+ " let object = if val.get().is_null_or_undefined() {\n"
+ " RootedObject::new(cx, ptr::null_mut())\n"
+ " } else if val.get().is_object() {\n"
+ " RootedObject::new(cx, val.get().to_object())\n"
" } else {\n"
" throw_type_error(cx, \"Value not an object.\");\n"
" return Err(());\n"
@@ -4557,10 +4898,10 @@ class CGDictionary(CGThing):
"}\n"
"\n"
"impl ToJSValConvertible for ${selfName} {\n"
- " fn to_jsval(&self, cx: *mut JSContext) -> JSVal {\n"
- " let obj = unsafe { JS_NewObject(cx, 0 as *const JSClass, 0 as *const JSObject, 0 as *const JSObject) };\n"
+ " fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {\n"
+ " let obj = unsafe { RootedObject::new(cx, JS_NewObject(cx, ptr::null())) };\n"
"${insertMembers}"
- " ObjectOrNullValue(obj)\n"
+ " rval.set(ObjectOrNullValue(obj.ptr))\n"
" }\n"
"}\n").substitute({
"selfName": self.makeClassName(d),
@@ -4587,7 +4928,7 @@ class CGDictionary(CGThing):
declType = CGWrapper(info.declType, pre="Option<", post=">")
return declType.define()
- def getMemberConversion(self, memberInfo):
+ def getMemberConversion(self, memberInfo, memberType):
def indent(s):
return CGIndenter(CGGeneric(s), 8).define()
@@ -4595,8 +4936,10 @@ class CGDictionary(CGThing):
templateBody = info.template
default = info.default
declType = info.declType
- replacements = { "val": "value" }
+ replacements = { "val": "rval.handle()" }
conversion = string.Template(templateBody).substitute(replacements)
+ if memberType.isAny():
+ conversion = "%s.get()" % conversion
assert (member.defaultValue is None) == (default is None)
if not default:
@@ -4604,14 +4947,16 @@ class CGDictionary(CGThing):
conversion = "Some(%s)" % conversion
conversion = (
- "match try!(get_dictionary_property(cx, object, \"%s\")) {\n"
- " Some(value) => {\n"
+ "{\n"
+ "let mut rval = RootedValue::new(cx, UndefinedValue());\n"
+ "match try!(get_dictionary_property(cx, object.handle(), \"%s\", rval.handle_mut())) {\n"
+ " true => {\n"
"%s\n"
" },\n"
- " None => {\n"
+ " false => {\n"
"%s\n"
" },\n"
- "}") % (member.identifier.name, indent(conversion), indent(default))
+ "}\n}") % (member.identifier.name, indent(conversion), indent(default))
return CGGeneric(conversion)
@@ -4641,7 +4986,7 @@ class CGRegisterProtos(CGAbstractMethod):
def __init__(self, config):
arguments = [
Argument('*mut JSContext', 'cx'),
- Argument('*mut JSObject', 'global'),
+ Argument('HandleObject', 'global'),
]
CGAbstractMethod.__init__(self, None, 'Register', 'void', arguments,
unsafe=False, pub=True)
@@ -4732,38 +5077,41 @@ class CGBindingRoot(CGThing):
# Add imports
curr = CGImports(curr, descriptors + callbackDescriptors, mainCallbacks, [
'js',
- 'js::{JS_ARGV, JS_CALLEE, JS_THIS_OBJECT}',
- 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS}',
+ 'js::JS_CALLEE',
+ 'js::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_DOMJSCLASS, JSCLASS_IMPLEMENTS_BARRIERS}',
'js::{JSCLASS_IS_GLOBAL, JSCLASS_RESERVED_SLOTS_SHIFT}',
- 'js::{JSCLASS_RESERVED_SLOTS_MASK, JSID_VOID, JSJitInfo}',
- 'js::{JSPROP_ENUMERATE, JSPROP_NATIVE_ACCESSORS, JSPROP_SHARED}',
- 'js::{JSRESOLVE_ASSIGNING, JSRESOLVE_QUALIFIED}',
+ 'js::{JSCLASS_RESERVED_SLOTS_MASK}',
+ 'js::{JSPROP_ENUMERATE, JSPROP_SHARED}',
'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_HasProperty, JS_HasPropertyById, JS_IsExceptionPending}',
- 'js::jsapi::{JS_NewObject, JS_ObjectIsCallable, JS_SetProperty, JS_SetPrototype}',
- 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSBool, JSContext}',
- 'js::jsapi::{JSClass, JSFreeOp, JSFunctionSpec, JSHandleObject, jsid}',
- 'js::jsapi::{JSNativeWrapper, JSObject, JSPropertyDescriptor, JS_ArrayIterator}',
- 'js::jsapi::{JSPropertyOpWrapper, JSPropertySpec, JS_PropertyStub}',
- 'js::jsapi::{JSStrictPropertyOpWrapper, JSString, JSTracer, JS_ConvertStub}',
- 'js::jsapi::{JS_StrictPropertyStub, JS_EnumerateStub, JS_ResolveStub}',
- 'js::jsapi::{JSMutableHandleValue, JSHandleId, JSType}',
+ 'js::jsapi::{JS_NewObjectWithGivenProto, JS_NewObject, IsCallable, JS_SetProperty, JS_SetPrototype}',
+ 'js::jsapi::{JS_SetReservedSlot, JS_WrapValue, JSContext}',
+ 'js::jsapi::{JSClass, FreeOp, JSFreeOp, JSFunctionSpec, jsid}',
+ 'js::jsapi::{MutableHandleValue, MutableHandleObject, HandleObject, HandleValue, RootedObject, RootedValue}',
+ 'js::jsapi::{JSNativeWrapper, JSNative, JSObject, JSPropertyDescriptor}',
+ 'js::jsapi::{JSPropertySpec}',
+ 'js::jsapi::{JSString, JSTracer, JSJitInfo, JSJitInfo_OpType, JSJitInfo_AliasSet}',
+ 'js::jsapi::{MutableHandle, Handle, HandleId, JSType, JSValueType}',
+ 'js::jsapi::{SymbolCode, ObjectOpResult, HandleValueArray}',
+ 'js::jsapi::{JSJitGetterCallArgs, JSJitSetterCallArgs, JSJitMethodCallArgs, CallArgs}',
+ 'js::jsapi::{JSAutoCompartment, JSAutoRequest, JS_ComputeThis}',
+ 'js::jsapi::GetGlobalForObjectCrossCompartment',
'js::jsval::JSVal',
'js::jsval::{ObjectValue, ObjectOrNullValue, PrivateValue}',
'js::jsval::{NullValue, UndefinedValue}',
- 'js::glue::{CallJitMethodOp, CallJitPropertyOp, CreateProxyHandler}',
- 'js::glue::{GetProxyPrivate, NewProxyObject, ProxyTraps, AutoIdVector}',
+ 'js::glue::{CallJitMethodOp, CallJitGetterOp, CallJitSetterOp, 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::rust::GCMethods',
+ 'js::{JSTrue, JSFalse}',
'dom::bindings',
'dom::bindings::global::GlobalRef',
'dom::bindings::global::global_object_for_js_object',
- 'dom::bindings::js::{JS, JSRef, Root, RootedReference, Temporary, Unrooted}',
- 'dom::bindings::js::{OptionalOptionalRootable, OptionalRootable}',
- 'dom::bindings::js::{OptionalRootedReference, ResultRootable, Rootable}',
+ 'dom::bindings::js::{JS, Root, RootedReference}',
+ 'dom::bindings::js::{OptionalRootedReference}',
'dom::bindings::utils::{create_dom_global, do_create_interface_objects}',
'dom::bindings::utils::ConstantSpec',
'dom::bindings::utils::{DOMClass}',
@@ -4780,16 +5128,16 @@ class CGBindingRoot(CGThing):
'dom::bindings::utils::{NativeProperties, NativePropertyHooks}',
'dom::bindings::utils::ConstantVal::{IntVal, UintVal}',
'dom::bindings::utils::NonNullJSNative',
- 'dom::bindings::trace::JSTraceable',
+ 'dom::bindings::trace::{JSTraceable, RootedTraceable}',
'dom::bindings::callback::{CallbackContainer,CallbackInterface,CallbackFunction}',
'dom::bindings::callback::{CallSetup,ExceptionHandling}',
'dom::bindings::callback::wrap_call_this_object',
'dom::bindings::conversions::{FromJSValConvertible, ToJSValConvertible}',
- 'dom::bindings::conversions::{native_from_reflector, native_from_reflector_jsmanaged}',
+ 'dom::bindings::conversions::{native_from_reflector, native_from_handlevalue, native_from_handleobject}',
'dom::bindings::conversions::DOM_OBJECT_SLOT',
'dom::bindings::conversions::IDLInterface',
'dom::bindings::conversions::jsid_to_str',
- 'dom::bindings::conversions::StringificationBehavior::{Default, Empty}',
+ 'dom::bindings::conversions::StringificationBehavior',
'dom::bindings::codegen::{PrototypeList, RegisterBindings, UnionTypes}',
'dom::bindings::codegen::Bindings::*',
'dom::bindings::error::{Fallible, Error, ErrorResult}',
@@ -4812,6 +5160,10 @@ class CGBindingRoot(CGThing):
'std::num',
'std::ptr',
'std::str',
+ 'std::rc',
+ 'std::rc::Rc',
+ 'std::default::Default',
+ 'std::ffi::CString',
])
# Add the auto-generated comment.
@@ -4918,7 +5270,7 @@ class CGCallback(CGClass):
bases=[ClassBase(baseName)],
constructors=self.getConstructors(),
methods=realMethods+getters+setters,
- decorators="#[derive(PartialEq,Copy,Clone)]#[jstraceable]")
+ decorators="#[derive(PartialEq)]#[jstraceable]")
def getConstructors(self):
return [ClassConstructor(
@@ -4927,7 +5279,7 @@ class CGCallback(CGClass):
visibility="pub",
explicit=False,
baseConstructors=[
- "%s::new(aCallback)" % self.baseName
+ "%s::new()" % self.baseName
])]
def getMethodImpls(self, method):
@@ -4936,13 +5288,13 @@ class CGCallback(CGClass):
# Strip out the JSContext*/JSObject* args
# that got added.
assert args[0].name == "cx" and args[0].argType == "*mut JSContext"
- assert args[1].name == "aThisObj" and args[1].argType == "*mut JSObject"
+ assert args[1].name == "aThisObj" and args[1].argType == "HandleObject"
args = args[2:]
# Record the names of all the arguments, so we can use them when we call
# the private method.
argnames = [arg.name for arg in args]
- argnamesWithThis = ["s.get_context()", "thisObjJS"] + argnames
- argnamesWithoutThis = ["s.get_context()", "ptr::null_mut()"] + argnames
+ argnamesWithThis = ["s.get_context()", "thisObjJS.handle()"] + argnames
+ argnamesWithoutThis = ["s.get_context()", "thisObjJS.handle()"] + argnames
# Now that we've recorded the argnames for our call to our private
# method, insert our optional argument for deciding whether the
# CallSetup should re-throw exceptions on aRv.
@@ -4951,12 +5303,12 @@ class CGCallback(CGClass):
# And now insert our template argument.
argsWithoutThis = list(args)
- args.insert(0, Argument("JSRef<T>", "thisObj"))
+ args.insert(0, Argument("&T", "thisObj"))
# And the self argument
- method.args.insert(0, Argument(None, "self"))
- args.insert(0, Argument(None, "self"))
- argsWithoutThis.insert(0, Argument(None, "self"))
+ method.args.insert(0, Argument(None, "&self"))
+ args.insert(0, Argument(None, "&self"))
+ argsWithoutThis.insert(0, Argument(None, "&self"))
setupCall = ("let s = CallSetup::new(self, aExceptionHandling);\n"
"if s.get_context().is_null() {\n"
@@ -4965,8 +5317,9 @@ class CGCallback(CGClass):
bodyWithThis = string.Template(
setupCall+
- "let thisObjJS = wrap_call_this_object(s.get_context(), thisObj);\n"
- "if thisObjJS.is_null() {\n"
+ "let mut thisObjJS = RootedObject::new(s.get_context(), ptr::null_mut());\n"
+ "wrap_call_this_object(s.get_context(), thisObj, thisObjJS.handle_mut());\n"
+ "if thisObjJS.ptr.is_null() {\n"
" return Err(JSFailed);\n"
"}\n"
"return ${methodName}(${callArgs});").substitute({
@@ -4975,6 +5328,7 @@ class CGCallback(CGClass):
})
bodyWithoutThis = string.Template(
setupCall +
+ "let thisObjJS = RootedObject::new(s.get_context(), ptr::null_mut());"
"return ${methodName}(${callArgs});").substitute({
"callArgs" : ", ".join(argnamesWithoutThis),
"methodName": 'self.' + method.name,
@@ -5017,7 +5371,7 @@ class CGCallbackFunctionImpl(CGGeneric):
def __init__(self, callback):
impl = string.Template("""\
impl CallbackContainer for ${type} {
- fn new(callback: *mut JSObject) -> ${type} {
+ fn new(callback: *mut JSObject) -> Rc<${type}> {
${type}::new(callback)
}
@@ -5027,8 +5381,8 @@ impl CallbackContainer for ${type} {
}
impl ToJSValConvertible for ${type} {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- self.callback().to_jsval(cx)
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ self.callback().to_jsval(cx, rval);
}
}\
""").substitute({"type": callback.name})
@@ -5127,14 +5481,12 @@ class CallbackMember(CGNativeMember):
"${returnResult}").substitute(replacements)
return CGList([
CGGeneric(pre),
- CGWrapper(CGIndenter(CGGeneric(body)),
- pre="with_compartment(cx, self.parent.callback(), || {\n",
- post="})")
+ CGGeneric(body),
], "\n").define()
def getResultConversion(self):
replacements = {
- "val": "rval",
+ "val": "rval.handle()",
}
info = getJSToNativeConversionInfo(
@@ -5153,6 +5505,8 @@ class CallbackMember(CGNativeMember):
if self.retvalType is None or self.retvalType.isVoid():
retval = "()"
+ elif self.retvalType.isAny():
+ retval = "rvalDecl.get()"
else:
retval = "rvalDecl"
@@ -5177,16 +5531,17 @@ class CallbackMember(CGNativeMember):
argval = arg.identifier.name
if arg.variadic:
- argval = argval + "[idx]"
+ argval = argval + "[idx].get()"
jsvalIndex = "%d + idx" % i
else:
jsvalIndex = "%d" % i
if arg.optional and not arg.defaultValue:
argval += ".clone().unwrap()"
- conversion = wrapForType("argv[%s]" % jsvalIndex,
- result=argval,
- successCode="")
+ conversion = wrapForType(
+ "argv_root.handle_mut()", result=argval,
+ successCode="argv[%s] = argv_root.ptr;" % jsvalIndex,
+ pre="let mut argv_root = RootedValue::new(cx, UndefinedValue());")
if arg.variadic:
conversion = string.Template(
"for idx in 0..${arg}.len() {\n" +
@@ -5216,7 +5571,7 @@ class CallbackMember(CGNativeMember):
# We want to allow the caller to pass in a "this" object, as
# well as a JSContext.
return [Argument("*mut JSContext", "cx"),
- Argument("*mut JSObject", "aThisObj")] + args
+ Argument("HandleObject", "aThisObj")] + args
def getCallSetup(self):
if self.needThisHandling:
@@ -5230,7 +5585,7 @@ class CallbackMember(CGNativeMember):
"}\n")
def getArgcDecl(self):
- return CGGeneric("let mut argc = %s as u32;" % self.argCountStr);
+ return CGGeneric("let mut argc = %s;" % self.argCountStr);
@staticmethod
def ensureASCIIName(idlObject):
@@ -5252,7 +5607,7 @@ class CallbackMethod(CallbackMember):
CallbackMember.__init__(self, sig, name, descriptorProvider,
needThisHandling)
def getRvalDecl(self):
- return "let mut rval = UndefinedValue();\n"
+ return "let mut rval = RootedValue::new(cx, UndefinedValue());\n"
def getCall(self):
replacements = {
@@ -5260,15 +5615,16 @@ class CallbackMethod(CallbackMember):
"getCallable": self.getCallableDecl()
}
if self.argCount > 0:
- replacements["argv"] = "argv.as_mut_ptr()"
+ replacements["argv"] = "argv.as_ptr()"
replacements["argc"] = "argc"
else:
replacements["argv"] = "ptr::null_mut()"
replacements["argc"] = "0"
return string.Template("${getCallable}"
"let ok = unsafe {\n"
- " JS_CallFunctionValue(cx, ${thisObj}, callable,\n"
- " ${argc}, ${argv}, &mut rval)\n"
+ " let rootedThis = RootedObject::new(cx, ${thisObj});\n"
+ " JS_CallFunctionValue(cx, rootedThis.handle(), callable.handle(),\n"
+ " &HandleValueArray { length_: ${argc} as ::libc::size_t, elements_: ${argv} }, rval.handle_mut())\n"
"};\n"
"if ok == 0 {\n"
" return Err(JSFailed);\n"
@@ -5280,10 +5636,10 @@ class CallCallback(CallbackMethod):
descriptorProvider, needThisHandling=True)
def getThisObj(self):
- return "aThisObj"
+ return "aThisObj.get()"
def getCallableDecl(self):
- return "let callable = ObjectValue(unsafe {&*self.parent.callback()});\n"
+ return "let callable = RootedValue::new(cx, ObjectValue(unsafe {&*self.parent.callback()}));\n"
class CallbackOperationBase(CallbackMethod):
"""
@@ -5300,23 +5656,23 @@ class CallbackOperationBase(CallbackMethod):
# This relies on getCallableDecl declaring a boolean
# isCallable in the case when we're a single-operation
# interface.
- return "if isCallable { aThisObj } else { self.parent.callback() }"
+ return "if isCallable { aThisObj.get() } else { self.parent.callback() }"
def getCallableDecl(self):
replacements = {
"methodName": self.methodName
}
getCallableFromProp = string.Template(
- 'try!(self.parent.get_callable_property(cx, "${methodName}"))'
+ 'RootedValue::new(cx, try!(self.parent.get_callable_property(cx, "${methodName}")))'
).substitute(replacements)
if not self.singleOperation:
return 'JS::Rooted<JS::Value> callable(cx);\n' + getCallableFromProp
return (
- 'let isCallable = unsafe { JS_ObjectIsCallable(cx, self.parent.callback()) != 0 };\n'
+ 'let isCallable = unsafe { IsCallable(self.parent.callback()) != 0 };\n'
'let callable =\n' +
CGIndenter(
CGIfElseWrapper('isCallable',
- CGGeneric('unsafe { ObjectValue(&*self.parent.callback()) }'),
+ CGGeneric('unsafe { RootedValue::new(cx, ObjectValue(&*self.parent.callback())) }'),
CGGeneric(getCallableFromProp))).define() + ';\n')
class CallbackOperation(CallbackOperationBase):
@@ -5399,7 +5755,7 @@ class GlobalGenRoots():
return CGList([
CGGeneric(AUTOGENERATED_WARNING_COMMENT),
CGGeneric("pub const MAX_PROTO_CHAIN_LENGTH: usize = %d;\n\n" % config.maxProtoChainLength),
- CGNonNamespacedEnum('ID', protos, [0], deriving="PartialEq, Copy, Clone"),
+ CGNonNamespacedEnum('ID', protos, [0], deriving="PartialEq, Copy, Clone", repr="u16"),
CGNonNamespacedEnum('Proxies', proxies, [0], deriving="PartialEq, Copy, Clone"),
])
@@ -5416,7 +5772,7 @@ class GlobalGenRoots():
'dom::bindings::codegen',
'dom::bindings::codegen::PrototypeList::Proxies',
'js::jsapi::JSContext',
- 'js::jsapi::JSObject',
+ 'js::jsapi::HandleObject',
'libc',
], ignored_warnings=[])
@@ -5442,7 +5798,7 @@ class GlobalGenRoots():
descriptors = config.getDescriptors(register=True, isCallback=False)
allprotos = [CGGeneric("use dom::types::*;\n"),
- CGGeneric("use dom::bindings::js::{JS, JSRef, LayoutJS, Rootable, Temporary};\n"),
+ CGGeneric("use dom::bindings::js::{JS, LayoutJS, Root};\n"),
CGGeneric("use dom::bindings::trace::JSTraceable;\n"),
CGGeneric("use dom::bindings::utils::Reflectable;\n"),
CGGeneric("use js::jsapi::JSTracer;\n\n"),
@@ -5476,7 +5832,7 @@ impl ${selfName} for ${baseName} {
pub struct ${name}Cast;
impl ${name}Cast {
#[inline]
- pub fn to_ref<'a, T: ${toBound}+Reflectable>(base: JSRef<'a, T>) -> Option<JSRef<'a, ${name}>> {
+ pub fn to_ref<'a, T: ${toBound}+Reflectable>(base: &'a T) -> Option<&'a ${name}> {
match base.${checkFn}() {
true => Some(unsafe { mem::transmute(base) }),
false => None
@@ -5484,7 +5840,7 @@ impl ${name}Cast {
}
#[inline]
- pub fn to_borrowed_ref<'a, 'b, T: ${toBound}+Reflectable>(base: &'a JSRef<'b, T>) -> Option<&'a JSRef<'b, ${name}>> {
+ pub fn to_borrowed_ref<'a, 'b, T: ${toBound}+Reflectable>(base: &'a &'b T) -> Option<&'a &'b ${name}> {
match base.${checkFn}() {
true => Some(unsafe { mem::transmute(base) }),
false => None
@@ -5503,20 +5859,20 @@ impl ${name}Cast {
}
#[inline]
- pub fn to_temporary<T: ${toBound}+Reflectable>(base: Temporary<T>) -> Option<Temporary<${name}>> {
- match base.root().r().${checkFn}() {
+ pub fn to_root<T: ${toBound}+Reflectable>(base: Root<T>) -> Option<Root<${name}>> {
+ match base.r().${checkFn}() {
true => Some(unsafe { mem::transmute(base) }),
false => None
}
}
#[inline]
- pub fn from_ref<'a, T: ${fromBound}+Reflectable>(derived: JSRef<'a, T>) -> JSRef<'a, ${name}> {
+ pub fn from_ref<'a, T: ${fromBound}+Reflectable>(derived: &'a T) -> &'a ${name} {
unsafe { mem::transmute(derived) }
}
#[inline]
- pub fn from_borrowed_ref<'a, 'b, T: ${fromBound}+Reflectable>(derived: &'a JSRef<'b, T>) -> &'a JSRef<'b, ${name}> {
+ pub fn from_borrowed_ref<'a, 'b, T: ${fromBound}+Reflectable>(derived: &'a &'b T) -> &'a &'b ${name} {
unsafe { mem::transmute(derived) }
}
@@ -5527,7 +5883,7 @@ impl ${name}Cast {
}
#[inline]
- pub fn from_temporary<T: ${fromBound}+Reflectable>(derived: Temporary<T>) -> Temporary<${name}> {
+ pub fn from_root<T: ${fromBound}+Reflectable>(derived: Root<T>) -> Root<${name}> {
unsafe { mem::transmute(derived) }
}
diff --git a/components/script/dom/bindings/codegen/Configuration.py b/components/script/dom/bindings/codegen/Configuration.py
index 8741cb9eacf..6e4bcbed34c 100644
--- a/components/script/dom/bindings/codegen/Configuration.py
+++ b/components/script/dom/bindings/codegen/Configuration.py
@@ -148,16 +148,16 @@ class Descriptor(DescriptorProvider):
if self.interface.isCallback():
self.needsRooting = False
ty = "%sBinding::%s" % (ifaceName, ifaceName)
- self.returnType = ty
+ self.returnType = "Rc<%s>"% ty
self.argumentType = "???"
self.memberType = "???"
self.nativeType = ty
else:
self.needsRooting = True
- self.returnType = "Temporary<%s>" % ifaceName
- self.argumentType = "JSRef<%s>" % ifaceName
+ self.returnType = "Root<%s>" % ifaceName
+ self.argumentType = "&%s" % ifaceName
self.memberType = "Root<%s>" % ifaceName
- self.nativeType = "Unrooted<%s>" % ifaceName
+ self.nativeType = "Root<%s>" % ifaceName
self.concreteType = ifaceName
self.register = desc.get('register', True)
diff --git a/components/script/dom/bindings/conversions.rs b/components/script/dom/bindings/conversions.rs
index 089193cca43..317744907c7 100644
--- a/components/script/dom/bindings/conversions.rs
+++ b/components/script/dom/bindings/conversions.rs
@@ -24,17 +24,17 @@
//! | USVString | `USVString` |
//! | ByteString | `ByteString` |
//! | object | `*mut JSObject` |
-//! | interface types | `JSRef<T>` | `Temporary<T>` |
+//! | interface types | `&T` | `Root<T>` |
//! | dictionary types | `&T` | *unsupported* |
//! | enumeration types | `T` |
-//! | callback function types | `T` |
+//! | callback function types | `Rc<T>` |
//! | nullable types | `Option<T>` |
//! | sequences | `Vec<T>` |
//! | union types | `T` |
use dom::bindings::codegen::PrototypeList;
use dom::bindings::error::throw_type_error;
-use dom::bindings::js::{JSRef, Root, Unrooted};
+use dom::bindings::js::Root;
use dom::bindings::num::Finite;
use dom::bindings::str::{ByteString, USVString};
use dom::bindings::utils::{Reflectable, Reflector, DOMClass};
@@ -43,14 +43,15 @@ use util::str::DOMString;
use js;
use js::glue::{RUST_JSID_TO_STRING, RUST_JSID_IS_STRING};
use js::glue::RUST_JS_NumberValue;
-use js::jsapi::{JSBool, JSContext, JSObject, JSString, jsid};
-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::rust::{ToUint64, ToInt64};
+use js::rust::{ToUint32, ToInt32};
+use js::rust::{ToUint16, ToNumber, ToBoolean, ToString};
+use js::jsapi::{JSContext, JSObject, JSString};
+use js::jsapi::{JS_StringHasLatin1Chars, JS_GetLatin1StringCharsAndLength, JS_GetTwoByteStringCharsAndLength};
use js::jsapi::{JS_NewUCStringCopyN, JS_NewStringCopyN};
use js::jsapi::{JS_WrapValue};
use js::jsapi::{JSClass, JS_GetClass};
+use js::jsapi::{HandleId, HandleValue, HandleObject, MutableHandleValue};
use js::jsval::JSVal;
use js::jsval::{UndefinedValue, NullValue, BooleanValue, Int32Value, UInt32Value};
use js::jsval::{StringValue, ObjectValue, ObjectOrNullValue};
@@ -60,6 +61,9 @@ use num::Float;
use std::borrow::ToOwned;
use std::default;
use std::slice;
+use std::ptr;
+use std::rc::Rc;
+use core::nonzero::NonZero;
/// A trait to retrieve the constants necessary to check if a `JSObject`
/// implements a given interface.
@@ -74,7 +78,7 @@ pub trait IDLInterface {
/// A trait to convert Rust types to `JSVal`s.
pub trait ToJSValConvertible {
/// Convert `self` to a `JSVal`. JSAPI failure causes a task failure.
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal;
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue);
}
/// A trait to convert `JSVal`s to Rust types.
@@ -85,206 +89,201 @@ pub trait FromJSValConvertible {
/// Optional configuration of type `T` can be passed as the `option`
/// argument.
/// If it returns `Err(())`, a JSAPI exception is pending.
- fn from_jsval(cx: *mut JSContext, val: JSVal, option: Self::Config) -> Result<Self, ()>;
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, option: Self::Config) -> Result<Self, ()>;
}
impl ToJSValConvertible for () {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
- UndefinedValue()
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(UndefinedValue());
}
}
impl ToJSValConvertible for JSVal {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- let mut value = *self;
- if unsafe { JS_WrapValue(cx, &mut value) } == 0 {
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(*self);
+ if unsafe { JS_WrapValue(cx, rval) } == 0 {
panic!("JS_WrapValue failed.");
}
- value
}
}
-unsafe fn convert_from_jsval<T: default::Default>(
- cx: *mut JSContext, value: JSVal,
- convert_fn: unsafe extern "C" fn(*mut JSContext, JSVal, *mut T) -> JSBool) -> Result<T, ()> {
- let mut ret = default::Default::default();
- if convert_fn(cx, value, &mut ret) == 0 {
- Err(())
- } else {
- Ok(ret)
+impl ToJSValConvertible for HandleValue {
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(self.get());
+ if unsafe { JS_WrapValue(cx, rval) } == 0 {
+ panic!("JS_WrapValue failed.");
+ }
}
}
-
impl ToJSValConvertible for bool {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
- BooleanValue(*self)
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(BooleanValue(*self));
}
}
impl FromJSValConvertible for bool {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<bool, ()> {
- let result = unsafe { convert_from_jsval(cx, val, JS_ValueToBoolean) };
- result.map(|b| b != 0)
+ fn from_jsval(_cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<bool, ()> {
+ Ok(ToBoolean(val))
}
}
impl ToJSValConvertible for i8 {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
- Int32Value(*self as i32)
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(Int32Value(*self as i32));
}
}
impl FromJSValConvertible for i8 {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i8, ()> {
- let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) };
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<i8, ()> {
+ let result = ToInt32(cx, val);
result.map(|v| v as i8)
}
}
impl ToJSValConvertible for u8 {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
- Int32Value(*self as i32)
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(Int32Value(*self as i32));
}
}
impl FromJSValConvertible for u8 {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u8, ()> {
- let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) };
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<u8, ()> {
+ let result = ToInt32(cx, val);
result.map(|v| v as u8)
}
}
impl ToJSValConvertible for i16 {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
- Int32Value(*self as i32)
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(Int32Value(*self as i32));
}
}
impl FromJSValConvertible for i16 {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i16, ()> {
- let result = unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) };
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<i16, ()> {
+ let result = ToInt32(cx, val);
result.map(|v| v as i16)
}
}
impl ToJSValConvertible for u16 {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
- Int32Value(*self as i32)
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(Int32Value(*self as i32));
}
}
impl FromJSValConvertible for u16 {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u16, ()> {
- unsafe { convert_from_jsval(cx, val, JS_ValueToUint16) }
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<u16, ()> {
+ ToUint16(cx, val)
}
}
impl ToJSValConvertible for i32 {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
- Int32Value(*self)
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(Int32Value(*self));
}
}
impl FromJSValConvertible for i32 {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i32, ()> {
- unsafe { convert_from_jsval(cx, val, JS_ValueToECMAInt32) }
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<i32, ()> {
+ ToInt32(cx, val)
}
}
impl ToJSValConvertible for u32 {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
- UInt32Value(*self)
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(UInt32Value(*self));
}
}
impl FromJSValConvertible for u32 {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u32, ()> {
- unsafe { convert_from_jsval(cx, val, JS_ValueToECMAUint32) }
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<u32, ()> {
+ ToUint32(cx, val)
}
}
impl ToJSValConvertible for i64 {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
unsafe {
- RUST_JS_NumberValue(*self as f64)
+ rval.set(RUST_JS_NumberValue(*self as f64));
}
}
}
impl FromJSValConvertible for i64 {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<i64, ()> {
- unsafe { convert_from_jsval(cx, val, JS_ValueToInt64) }
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<i64, ()> {
+ ToInt64(cx, val)
}
}
impl ToJSValConvertible for u64 {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
unsafe {
- RUST_JS_NumberValue(*self as f64)
+ rval.set(RUST_JS_NumberValue(*self as f64));
}
}
}
impl FromJSValConvertible for u64 {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<u64, ()> {
- unsafe { convert_from_jsval(cx, val, JS_ValueToUint64) }
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<u64, ()> {
+ ToUint64(cx, val)
}
}
impl ToJSValConvertible for f32 {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
unsafe {
- RUST_JS_NumberValue(*self as f64)
+ rval.set(RUST_JS_NumberValue(*self as f64));
}
}
}
impl FromJSValConvertible for f32 {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<f32, ()> {
- let result = unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) };
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<f32, ()> {
+ let result = ToNumber(cx, val);
result.map(|f| f as f32)
}
}
impl ToJSValConvertible for f64 {
- fn to_jsval(&self, _cx: *mut JSContext) -> JSVal {
+ fn to_jsval(&self, _cx: *mut JSContext, rval: MutableHandleValue) {
unsafe {
- RUST_JS_NumberValue(*self)
+ rval.set(RUST_JS_NumberValue(*self));
}
}
}
impl FromJSValConvertible for f64 {
type Config = ();
- fn from_jsval(cx: *mut JSContext, val: JSVal, _option: ()) -> Result<f64, ()> {
- unsafe { convert_from_jsval(cx, val, JS_ValueToNumber) }
+ fn from_jsval(cx: *mut JSContext, val: HandleValue, _option: ()) -> Result<f64, ()> {
+ ToNumber(cx, val)
}
}
impl<T: Float + ToJSValConvertible> ToJSValConvertible for Finite<T> {
#[inline]
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
let value = **self;
- value.to_jsval(cx)
+ value.to_jsval(cx, rval);
}
}
impl<T: Float + FromJSValConvertible<Config=()>> FromJSValConvertible for Finite<T> {
type Config = ();
- fn from_jsval(cx: *mut JSContext, value: JSVal, option: ()) -> Result<Finite<T>, ()> {
+ fn from_jsval(cx: *mut JSContext, value: HandleValue, option: ()) -> Result<Finite<T>, ()> {
let result = try!(FromJSValConvertible::from_jsval(cx, value, option));
match Finite::new(result) {
Some(v) => Ok(v),
@@ -297,21 +296,22 @@ impl<T: Float + FromJSValConvertible<Config=()>> FromJSValConvertible for Finite
}
impl ToJSValConvertible for str {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
unsafe {
let string_utf16: Vec<u16> = self.utf16_units().collect();
- let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr(), string_utf16.len() as libc::size_t);
+ let jsstr = JS_NewUCStringCopyN(cx, string_utf16.as_ptr() as *const i16,
+ string_utf16.len() as libc::size_t);
if jsstr.is_null() {
panic!("JS_NewUCStringCopyN failed");
}
- StringValue(&*jsstr)
+ rval.set(StringValue(&*jsstr));
}
}
}
impl ToJSValConvertible for DOMString {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- (**self).to_jsval(cx)
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ (**self).to_jsval(cx, rval);
}
}
@@ -333,18 +333,36 @@ impl default::Default for StringificationBehavior {
/// Convert the given `JSString` to a `DOMString`. Fails if the string does not
/// contain valid UTF-16.
pub fn jsstring_to_str(cx: *mut JSContext, s: *mut JSString) -> DOMString {
- unsafe {
- let mut length = 0;
- let chars = JS_GetStringCharsAndLength(cx, s, &mut length);
+ let mut length = 0;
+ let latin1 = unsafe { JS_StringHasLatin1Chars(s) != 0 };
+ if latin1 {
+ let chars = unsafe {
+ JS_GetLatin1StringCharsAndLength(cx, ptr::null(), s, &mut length)
+ };
+ assert!(!chars.is_null());
+
+ let mut buf = String::with_capacity(length as usize);
+ for i in 0..(length as isize) {
+ unsafe {
+ buf.push(*chars.offset(i) as char);
+ }
+ }
+ buf
+ } else {
+ let chars = unsafe {
+ JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), s, &mut length)
+ };
assert!(!chars.is_null());
- let char_vec = slice::from_raw_parts(chars, length as usize);
+ let char_vec = unsafe {
+ slice::from_raw_parts(chars as *const u16, length as usize)
+ };
String::from_utf16(char_vec).unwrap()
}
}
/// Convert the given `jsid` to a `DOMString`. Fails if the `jsid` is not a
/// string, or if the string does not contain valid UTF-16.
-pub fn jsid_to_str(cx: *mut JSContext, id: jsid) -> DOMString {
+pub fn jsid_to_str(cx: *mut JSContext, id: HandleId) -> DOMString {
unsafe {
assert!(RUST_JSID_IS_STRING(id) != 0);
jsstring_to_str(cx, RUST_JSID_TO_STRING(id))
@@ -353,15 +371,16 @@ pub fn jsid_to_str(cx: *mut JSContext, id: jsid) -> DOMString {
impl FromJSValConvertible for DOMString {
type Config = StringificationBehavior;
- fn from_jsval(cx: *mut JSContext, value: JSVal,
+ fn from_jsval(cx: *mut JSContext, value: HandleValue,
null_behavior: StringificationBehavior)
-> Result<DOMString, ()> {
- if null_behavior == StringificationBehavior::Empty && value.is_null() {
+ if null_behavior == StringificationBehavior::Empty &&
+ value.get().is_null() {
Ok("".to_owned())
} else {
- let jsstr = unsafe { JS_ValueToString(cx, value) };
+ let jsstr = ToString(cx, value);
if jsstr.is_null() {
- debug!("JS_ValueToString failed");
+ debug!("ToString failed");
Err(())
} else {
Ok(jsstring_to_str(cx, jsstr))
@@ -371,56 +390,75 @@ impl FromJSValConvertible for DOMString {
}
impl ToJSValConvertible for USVString {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- self.0.to_jsval(cx)
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ self.0.to_jsval(cx, rval);
}
}
impl FromJSValConvertible for USVString {
type Config = ();
- fn from_jsval(cx: *mut JSContext, value: JSVal, _: ())
+ fn from_jsval(cx: *mut JSContext, value: HandleValue, _: ())
-> Result<USVString, ()> {
- let jsstr = unsafe { JS_ValueToString(cx, value) };
+ let jsstr = ToString(cx, value);
if jsstr.is_null() {
- debug!("JS_ValueToString failed");
- Err(())
- } else {
- unsafe {
- let mut length = 0;
- let chars = JS_GetStringCharsAndLength(cx, jsstr, &mut length);
- assert!(!chars.is_null());
- let char_vec = slice::from_raw_parts(chars, length as usize);
- Ok(USVString(String::from_utf16_lossy(char_vec)))
- }
+ debug!("ToString failed");
+ return Err(());
+ }
+ let latin1 = unsafe { JS_StringHasLatin1Chars(jsstr) != 0 };
+ if latin1 {
+ return Ok(USVString(jsstring_to_str(cx, jsstr)));
+ }
+ unsafe {
+ let mut length = 0;
+ let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), jsstr, &mut length);
+ assert!(!chars.is_null());
+ let char_vec = slice::from_raw_parts(chars as *const u16, length as usize);
+ Ok(USVString(String::from_utf16_lossy(char_vec)))
}
}
}
impl ToJSValConvertible for ByteString {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
unsafe {
let jsstr = JS_NewStringCopyN(cx, self.as_ptr() as *const libc::c_char,
self.len() as libc::size_t);
if jsstr.is_null() {
panic!("JS_NewStringCopyN failed");
}
- StringValue(&*jsstr)
+ rval.set(StringValue(&*jsstr));
}
}
}
impl FromJSValConvertible for ByteString {
type Config = ();
- fn from_jsval(cx: *mut JSContext, value: JSVal, _option: ()) -> Result<ByteString, ()> {
- unsafe {
- let string = JS_ValueToString(cx, value);
- if string.is_null() {
- debug!("JS_ValueToString failed");
- return Err(());
- }
+ fn from_jsval(cx: *mut JSContext, value: HandleValue, _option: ()) -> Result<ByteString, ()> {
+ let string = ToString(cx, value);
+ if string.is_null() {
+ debug!("ToString failed");
+ return Err(());
+ }
+
+ let latin1 = unsafe { JS_StringHasLatin1Chars(string) != 0 };
+ if latin1 {
+ let mut length = 0;
+ let chars = unsafe {
+ JS_GetLatin1StringCharsAndLength(cx, ptr::null(),
+ string, &mut length)
+ };
+ assert!(!chars.is_null());
+
+ let char_vec = unsafe {
+ Vec::from_raw_buf(chars as *mut u8, length as usize)
+ };
+
+ return Ok(ByteString::new(char_vec));
+ }
+ unsafe {
let mut length = 0;
- let chars = JS_GetStringCharsAndLength(cx, string, &mut length);
+ let chars = JS_GetTwoByteStringCharsAndLength(cx, ptr::null(), string, &mut length);
let char_vec = slice::from_raw_parts(chars, length as usize);
if char_vec.iter().any(|&c| c > 0xFF) {
@@ -434,14 +472,13 @@ impl FromJSValConvertible for ByteString {
}
impl ToJSValConvertible for Reflector {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- let obj = self.get_jsobject();
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ let obj = self.get_jsobject().get();
assert!(!obj.is_null());
- let mut value = ObjectValue(unsafe { &*obj });
- if unsafe { JS_WrapValue(cx, &mut value) } == 0 {
+ rval.set(ObjectValue(unsafe { &*obj }));
+ if unsafe { JS_WrapValue(cx, rval) } == 0 {
panic!("JS_WrapValue failed.");
}
- value
}
}
@@ -454,11 +491,10 @@ pub 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 {
- use js::glue::{js_IsObjectProxyClass, js_IsFunctionProxyClass, IsProxyHandlerFamily};
-
+ use js::glue::IsProxyHandlerFamily;
unsafe {
- (js_IsObjectProxyClass(obj) || js_IsFunctionProxyClass(obj)) &&
- IsProxyHandlerFamily(obj)
+ let clasp = JS_GetClass(obj);
+ ((*clasp).flags & js::JSCLASS_IS_PROXY) != 0 && IsProxyHandlerFamily(obj) != 0
}
}
@@ -467,29 +503,24 @@ pub fn is_dom_proxy(obj: *mut JSObject) -> bool {
// We use slot 0 for holding the raw object. This is safe for both
// globals and non-globals.
pub const DOM_OBJECT_SLOT: u32 = 0;
-const DOM_PROXY_OBJECT_SLOT: u32 = js::JSSLOT_PROXY_PRIVATE;
-
-/// 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
- } else {
- assert!(is_dom_proxy(obj));
- DOM_PROXY_OBJECT_SLOT
- }
-}
/// Get the DOM object from the given reflector.
pub unsafe fn native_from_reflector<T>(obj: *mut JSObject) -> *const T {
use js::jsapi::JS_GetReservedSlot;
+ use js::glue::GetProxyPrivate;
- let slot = dom_object_slot(obj);
- let value = JS_GetReservedSlot(obj, slot);
- value.to_private() as *const T
+ let clasp = JS_GetClass(obj);
+ let value = if is_dom_class(clasp) {
+ JS_GetReservedSlot(obj, DOM_OBJECT_SLOT)
+ } else {
+ assert!(is_dom_proxy(obj));
+ GetProxyPrivate(obj)
+ };
+ if value.is_undefined() {
+ ptr::null()
+ } else {
+ value.to_private() as *const T
+ }
}
/// Get the `DOMClass` from `obj`, or `Err(())` if `obj` is not a DOM object.
@@ -518,17 +549,16 @@ unsafe fn get_dom_class(obj: *mut JSObject) -> Result<DOMClass, ()> {
/// Returns Err(()) if `obj` is an opaque security wrapper or if the object is
/// not a reflector for a DOM object of the given type (as defined by the
/// proto_id and proto_depth).
-pub fn native_from_reflector_jsmanaged<T>(mut obj: *mut JSObject) -> Result<Unrooted<T>, ()>
+pub fn native_from_reflector_jsmanaged<T>(mut obj: *mut JSObject) -> Result<Root<T>, ()>
where T: Reflectable + IDLInterface
{
use js::glue::{IsWrapper, UnwrapObject};
- use std::ptr;
unsafe {
let dom_class = try!(get_dom_class(obj).or_else(|_| {
if IsWrapper(obj) == 1 {
debug!("found wrapper");
- obj = UnwrapObject(obj, /* stopAtOuter = */ 0, ptr::null_mut());
+ obj = UnwrapObject(obj, /* stopAtOuter = */ 0);
if obj.is_null() {
debug!("unwrapping security wrapper failed");
Err(())
@@ -547,7 +577,9 @@ pub fn native_from_reflector_jsmanaged<T>(mut obj: *mut JSObject) -> Result<Unro
let proto_depth = <T as IDLInterface>::get_prototype_depth();
if dom_class.interface_chain[proto_depth] == proto_id {
debug!("good prototype");
- Ok(Unrooted::from_raw(native_from_reflector(obj)))
+ let native = native_from_reflector(obj);
+ assert!(!native.is_null());
+ Ok(Root::new(NonZero::new(native)))
} else {
debug!("bad prototype");
Err(())
@@ -555,37 +587,54 @@ pub fn native_from_reflector_jsmanaged<T>(mut obj: *mut JSObject) -> Result<Unro
}
}
+/// Get a Rooted<T> for a DOM object accessible from a HandleValue
+pub fn native_from_handlevalue<T>(v: HandleValue) -> Result<Root<T>, ()>
+ where T: Reflectable + IDLInterface
+{
+ native_from_reflector_jsmanaged(v.get().to_object())
+}
+
+/// Get a Rooted<T> for a DOM object accessible from a HandleObject
+pub fn native_from_handleobject<T>(obj: HandleObject) -> Result<Root<T>, ()>
+ where T: Reflectable + IDLInterface
+{
+ native_from_reflector_jsmanaged(obj.get())
+}
+
impl<T: Reflectable> ToJSValConvertible for Root<T> {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- self.r().reflector().to_jsval(cx)
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ self.r().reflector().to_jsval(cx, rval);
}
}
-impl<'a, T: Reflectable> ToJSValConvertible for JSRef<'a, T> {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- self.reflector().to_jsval(cx)
+impl<'a, T: Reflectable> ToJSValConvertible for &'a T {
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ self.reflector().to_jsval(cx, rval);
}
}
-impl<'a, T: Reflectable> ToJSValConvertible for Unrooted<T> {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- self.reflector().to_jsval(cx)
+impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ match self {
+ &Some(ref value) => value.to_jsval(cx, rval),
+ &None => rval.set(NullValue()),
+ }
}
}
-impl<T: ToJSValConvertible> ToJSValConvertible for Option<T> {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
+impl<T: ToJSValConvertible> ToJSValConvertible for Option<Rc<T>> {
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
match self {
- &Some(ref value) => value.to_jsval(cx),
- &None => NullValue(),
+ &Some(ref value) => (**value).to_jsval(cx, rval),
+ &None => rval.set(NullValue()),
}
}
}
impl<X: default::Default, T: FromJSValConvertible<Config=X>> FromJSValConvertible for Option<T> {
type Config = ();
- fn from_jsval(cx: *mut JSContext, value: JSVal, _: ()) -> Result<Option<T>, ()> {
- if value.is_null_or_undefined() {
+ fn from_jsval(cx: *mut JSContext, value: HandleValue, _: ()) -> Result<Option<T>, ()> {
+ if value.get().is_null_or_undefined() {
Ok(None)
} else {
let option: X = default::Default::default();
@@ -596,11 +645,10 @@ impl<X: default::Default, T: FromJSValConvertible<Config=X>> FromJSValConvertibl
}
impl ToJSValConvertible for *mut JSObject {
- fn to_jsval(&self, cx: *mut JSContext) -> JSVal {
- let mut wrapped = ObjectOrNullValue(*self);
+ fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
+ rval.set(ObjectOrNullValue(*self));
unsafe {
- assert!(JS_WrapValue(cx, &mut wrapped) != 0);
+ assert!(JS_WrapValue(cx, rval) != 0);
}
- wrapped
}
}
diff --git a/components/script/dom/bindings/error.rs b/components/script/dom/bindings/error.rs
index 7d1e7ecbdd6..d228679631a 100644
--- a/components/script/dom/bindings/error.rs
+++ b/components/script/dom/bindings/error.rs
@@ -6,20 +6,22 @@
use dom::bindings::conversions::ToJSValConvertible;
use dom::bindings::global::GlobalRef;
-use dom::bindings::js::Rootable;
use dom::domexception::{DOMException, DOMErrorName};
use util::str::DOMString;
-use js::jsapi::{JSContext, JSObject};
+use js::jsapi::{JSContext, JSObject, RootedValue};
use js::jsapi::{JS_IsExceptionPending, JS_SetPendingException, JS_ReportPendingException};
-use js::jsapi::{JS_ReportErrorNumber, JSErrorFormatString, JSEXN_TYPEERR, JSEXN_RANGEERR};
+use js::jsapi::{JS_ReportErrorNumber1, JSErrorFormatString, JSExnType};
use js::jsapi::{JS_SaveFrameChain, JS_RestoreFrameChain};
-use js::rust::with_compartment;
+use js::jsapi::JSAutoCompartment;
+use js::jsval::UndefinedValue;
+use js::JSFalse;
use libc;
use std::ffi::CString;
use std::ptr;
+use std::mem;
/// DOM exceptions that can be thrown by a native DOM method.
#[derive(Debug, Clone)]
@@ -116,10 +118,11 @@ pub fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef,
};
assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
- let exception = DOMException::new(global, code).root();
- let thrown = exception.to_jsval(cx);
+ let exception = DOMException::new(global, code);
+ let mut thrown = RootedValue::new(cx, UndefinedValue());
+ exception.to_jsval(cx, thrown.handle_mut());
unsafe {
- JS_SetPendingException(cx, thrown);
+ JS_SetPendingException(cx, thrown.handle());
}
}
@@ -128,9 +131,10 @@ pub fn report_pending_exception(cx: *mut JSContext, obj: *mut JSObject) {
unsafe {
if JS_IsExceptionPending(cx) != 0 {
let saved = JS_SaveFrameChain(cx);
- with_compartment(cx, obj, || {
+ {
+ let _ac = JSAutoCompartment::new(cx, obj);
JS_ReportPendingException(cx);
- });
+ }
if saved != 0 {
JS_RestoreFrameChain(cx);
}
@@ -158,25 +162,26 @@ static ERROR_FORMAT_STRING_STRING: [libc::c_char; 4] = [
static mut TYPE_ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString {
format: &ERROR_FORMAT_STRING_STRING as *const libc::c_char,
argCount: 1,
- exnType: JSEXN_TYPEERR as i16,
+ exnType: JSExnType::JSEXN_TYPEERR as i16,
};
/// Format string struct used to throw `RangeError`s.
static mut RANGE_ERROR_FORMAT_STRING: JSErrorFormatString = JSErrorFormatString {
format: &ERROR_FORMAT_STRING_STRING as *const libc::c_char,
argCount: 1,
- exnType: JSEXN_RANGEERR as i16,
+ exnType: JSExnType::JSEXN_RANGEERR as i16,
};
/// Callback used to throw javascript errors.
/// See throw_js_error for info about error_number.
unsafe extern fn get_error_message(_user_ref: *mut libc::c_void,
- _locale: *const libc::c_char,
- error_number: libc::c_uint) -> *const JSErrorFormatString
+ error_number: libc::c_uint)
+ -> *const JSErrorFormatString
{
- match error_number as i32 {
- JSEXN_TYPEERR => &TYPE_ERROR_FORMAT_STRING as *const JSErrorFormatString,
- JSEXN_RANGEERR => &RANGE_ERROR_FORMAT_STRING as *const JSErrorFormatString,
+ let num: JSExnType = mem::transmute(error_number);
+ match num {
+ JSExnType::JSEXN_TYPEERR => &TYPE_ERROR_FORMAT_STRING as *const JSErrorFormatString,
+ JSExnType::JSEXN_RANGEERR => &RANGE_ERROR_FORMAT_STRING as *const JSErrorFormatString,
_ => panic!("Bad js error number given to get_error_message: {}", error_number)
}
}
@@ -188,20 +193,18 @@ unsafe extern fn get_error_message(_user_ref: *mut libc::c_void,
fn throw_js_error(cx: *mut JSContext, error: &str, error_number: u32) {
let error = CString::new(error).unwrap();
unsafe {
- JS_ReportErrorNumber(cx,
- Some(get_error_message as
- unsafe extern "C" fn(*mut libc::c_void, *const libc::c_char,
- libc::c_uint) -> *const JSErrorFormatString),
+ JS_ReportErrorNumber1(cx,
+ Some(get_error_message),
ptr::null_mut(), error_number, error.as_ptr());
}
}
/// Throw a `TypeError` with the given message.
pub fn throw_type_error(cx: *mut JSContext, error: &str) {
- throw_js_error(cx, error, JSEXN_TYPEERR as u32);
+ throw_js_error(cx, error, JSExnType::JSEXN_TYPEERR as u32);
}
/// Throw a `RangeError` with the given message.
pub fn throw_range_error(cx: *mut JSContext, error: &str) {
- throw_js_error(cx, error, JSEXN_RANGEERR as u32);
+ throw_js_error(cx, error, JSExnType::JSEXN_RANGEERR as u32);
}
diff --git a/components/script/dom/bindings/global.rs b/components/script/dom/bindings/global.rs
index d1294173dd1..a6924fbb281 100644
--- a/components/script/dom/bindings/global.rs
+++ b/components/script/dom/bindings/global.rs
@@ -9,7 +9,7 @@
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::conversions::native_from_reflector_jsmanaged;
-use dom::bindings::js::{JS, JSRef, Rootable, Root, Unrooted};
+use dom::bindings::js::{JS, Root};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::DocumentHelpers;
use dom::workerglobalscope::{WorkerGlobalScope, WorkerGlobalScopeHelpers};
@@ -21,7 +21,7 @@ use msg::constellation_msg::{PipelineId, WorkerId};
use net_traits::ResourceTask;
use js::{JSCLASS_IS_GLOBAL, JSCLASS_IS_DOMJSCLASS};
-use js::glue::{GetGlobalForObjectCrossCompartment};
+use js::jsapi::{GetGlobalForObjectCrossCompartment};
use js::jsapi::{JSContext, JSObject};
use js::jsapi::{JS_GetClass};
use url::Url;
@@ -30,9 +30,9 @@ use url::Url;
#[derive(Copy, Clone)]
pub enum GlobalRef<'a> {
/// A reference to a `Window` object.
- Window(JSRef<'a, window::Window>),
+ Window(&'a window::Window),
/// A reference to a `WorkerGlobalScope` object.
- Worker(JSRef<'a, WorkerGlobalScope>),
+ Worker(&'a WorkerGlobalScope),
}
/// A stack-based rooted reference to a global object.
@@ -55,15 +55,6 @@ pub enum GlobalField {
Worker(JS<WorkerGlobalScope>),
}
-/// An unrooted reference to a global object.
-#[must_root]
-pub enum GlobalUnrooted {
- /// An unrooted reference to a `Window` object.
- Window(Unrooted<window::Window>),
- /// An unrooted reference to a `WorkerGlobalScope` object.
- Worker(Unrooted<WorkerGlobalScope>),
-}
-
impl<'a> GlobalRef<'a> {
/// Get the `JSContext` for the `JSRuntime` associated with the thread
/// this global object is on.
@@ -76,7 +67,7 @@ impl<'a> GlobalRef<'a> {
/// Extract a `Window`, causing task failure if the global object is not
/// a `Window`.
- pub fn as_window<'b>(&'b self) -> JSRef<'b, window::Window> {
+ pub fn as_window<'b>(&'b self) -> &'b window::Window {
match *self {
GlobalRef::Window(window) => window,
GlobalRef::Worker(_) => panic!("expected a Window scope"),
@@ -104,7 +95,7 @@ impl<'a> GlobalRef<'a> {
pub fn resource_task(&self) -> ResourceTask {
match *self {
GlobalRef::Window(ref window) => {
- let doc = window.Document().root();
+ let doc = window.Document();
let doc = doc.r();
let loader = doc.loader();
loader.resource_task.clone()
@@ -182,8 +173,8 @@ impl GlobalField {
/// Create a new `GlobalField` from a rooted reference.
pub fn from_rooted(global: &GlobalRef) -> GlobalField {
match *global {
- GlobalRef::Window(window) => GlobalField::Window(JS::from_rooted(window)),
- GlobalRef::Worker(worker) => GlobalField::Worker(JS::from_rooted(worker)),
+ GlobalRef::Window(window) => GlobalField::Window(JS::from_ref(window)),
+ GlobalRef::Worker(worker) => GlobalField::Worker(JS::from_ref(worker)),
}
}
@@ -196,30 +187,20 @@ impl GlobalField {
}
}
-impl GlobalUnrooted {
- /// Create a stack-bounded root for this reference.
- pub fn root(&self) -> GlobalRoot {
- match *self {
- GlobalUnrooted::Window(ref window) => GlobalRoot::Window(window.root()),
- GlobalUnrooted::Worker(ref worker) => GlobalRoot::Worker(worker.root()),
- }
- }
-}
-
/// Returns the global object of the realm that the given JS object was created in.
#[allow(unrooted_must_root)]
-pub fn global_object_for_js_object(obj: *mut JSObject) -> GlobalUnrooted {
+pub fn global_object_for_js_object(obj: *mut JSObject) -> GlobalRoot {
unsafe {
let global = GetGlobalForObjectCrossCompartment(obj);
let clasp = JS_GetClass(global);
assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0);
match native_from_reflector_jsmanaged(global) {
- Ok(window) => return GlobalUnrooted::Window(window),
+ Ok(window) => return GlobalRoot::Window(window),
Err(_) => (),
}
match native_from_reflector_jsmanaged(global) {
- Ok(worker) => return GlobalUnrooted::Worker(worker),
+ Ok(worker) => return GlobalRoot::Worker(worker),
Err(_) => (),
}
diff --git a/components/script/dom/bindings/js.rs b/components/script/dom/bindings/js.rs
index fc22078360f..400200c3df3 100644
--- a/components/script/dom/bindings/js.rs
+++ b/components/script/dom/bindings/js.rs
@@ -11,178 +11,32 @@
//!
//! Here is a brief overview of the important types:
//!
-//! - `JSRef<T>`: a freely-copyable reference to a rooted DOM object.
//! - `Root<T>`: a stack-based reference to a rooted DOM object.
//! - `JS<T>`: a reference to a DOM object that can automatically be traced by
//! the GC when encountered as a field of a Rust structure.
-//! - `Temporary<T>`: a reference to a DOM object that will remain rooted for
-//! the duration of its lifetime.
//!
-//! The rule of thumb is as follows:
+//! `JS<T>` does not allow access to their inner value without explicitly
+//! creating a stack-based root via the `root` method. This returns a `Root<T>`,
+//! which causes the JS-owned value to be uncollectable for the duration of the
+//! `Root` object's lifetime. A reference to the object can then be obtained
+//! from the `Root` object. These references are not allowed to outlive their
+//! originating `Root<T>`.
//!
-//! - All methods return `Temporary<T>`, to ensure the value remains alive
-//! until it is stored somewhere that is reachable by the GC.
-//! - All functions take `JSRef<T>` arguments, to ensure that they will remain
-//! uncollected for the duration of their usage.
-//! - All DOM structs contain `JS<T>` fields and derive the `JSTraceable`
-//! trait, to ensure that they are transitively marked as reachable by the GC
-//! if the enclosing value is reachable.
-//! - All methods for type `T` are implemented for `JSRef<T>`, to ensure that
-//! the self value will not be collected for the duration of the method call.
-//!
-//! Both `Temporary<T>` and `JS<T>` do not allow access to their inner value
-//! without explicitly creating a stack-based root via the `root` method
-//! through the `Rootable<T>` trait. This returns a `Root<T>`, which causes the
-//! JS-owned value to be uncollectable for the duration of the `Root` object's
-//! lifetime. A `JSRef<T>` can be obtained from a `Root<T>` by calling the `r`
-//! method. These `JSRef<T>` values are not allowed to outlive their
-//! originating `Root<T>`, to ensure that all interactions with the enclosed
-//! value only occur when said value is uncollectable, and will cause static
-//! lifetime errors if misused.
-//!
-//! Other miscellaneous helper traits:
-//!
-//! - `OptionalRootable` and `OptionalOptionalRootable`: make rooting `Option`
-//! values easy via a `root` method
-//! - `ResultRootable`: make rooting successful `Result` values easy
-//! - `TemporaryPushable`: allows mutating vectors of `JS<T>` with new elements
-//! of `JSRef`/`Temporary`
-//! - `RootedReference`: makes obtaining an `Option<JSRef<T>>` from an
-//! `Option<Root<T>>` easy
use dom::bindings::trace::JSTraceable;
-use dom::bindings::trace::RootedVec;
+use dom::bindings::trace::trace_reflector;
use dom::bindings::utils::{Reflector, Reflectable};
use dom::node::Node;
-use js::jsapi::JSObject;
-use js::jsval::JSVal;
+use js::jsapi::{JSObject, Heap, JSTracer};
+use js::jsval::{JSVal, UndefinedValue};
use layout_interface::TrustedNodeAddress;
use script_task::STACK_ROOTS;
use core::nonzero::NonZero;
-use libc;
use std::cell::{Cell, UnsafeCell};
use std::default::Default;
-use std::intrinsics::return_address;
-use std::marker::PhantomData;
use std::ops::Deref;
-/// An unrooted, JS-owned value. Must not be held across a GC.
-///
-/// This is used in particular to wrap pointers extracted from a reflector.
-#[must_root]
-pub struct Unrooted<T> {
- ptr: NonZero<*const T>
-}
-
-impl<T: Reflectable> Unrooted<T> {
- /// Create a new JS-owned value wrapped from a raw Rust pointer.
- pub unsafe fn from_raw(raw: *const T) -> Unrooted<T> {
- assert!(!raw.is_null());
- Unrooted {
- ptr: NonZero::new(raw)
- }
- }
-
- /// Create a new unrooted value from a `JS<T>`.
- #[allow(unrooted_must_root)]
- pub fn from_js(ptr: JS<T>) -> Unrooted<T> {
- Unrooted {
- ptr: ptr.ptr
- }
- }
-
- /// Create a new unrooted value from a `Temporary<T>`.
- #[allow(unrooted_must_root)]
- pub fn from_temporary(ptr: Temporary<T>) -> Unrooted<T> {
- Unrooted::from_js(ptr.inner)
- }
-
- /// Get the `Reflector` for this pointer.
- pub fn reflector<'a>(&'a self) -> &'a Reflector {
- unsafe {
- (**self.ptr).reflector()
- }
- }
-
- /// Returns an unsafe pointer to the interior of this object.
- pub unsafe fn unsafe_get(&self) -> *const T {
- *self.ptr
- }
-}
-
-impl<T: Reflectable> Rootable<T> for Unrooted<T> {
- /// Create a stack-bounded root for this value.
- fn root(&self) -> Root<T> {
- STACK_ROOTS.with(|ref collection| {
- let RootCollectionPtr(collection) = collection.get().unwrap();
- unsafe {
- Root::new(&*collection, self.ptr)
- }
- })
- }
-}
-
-impl<T> Copy for Unrooted<T> {}
-impl<T> Clone for Unrooted<T> {
- fn clone(&self) -> Unrooted<T> { *self }
-}
-
-/// 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. Can be assigned into JS-owned member fields (i.e.
-/// `JS<T>` types) safely via the `JS<T>::assign` method or
-/// `OptionalSettable::assign` (for `Option<JS<T>>` fields).
-#[allow(unrooted_must_root)]
-pub struct Temporary<T> {
- inner: JS<T>,
- /// On-stack JS pointer to assuage conservative stack scanner
- _js_ptr: *mut JSObject,
-}
-
-impl<T> Clone for Temporary<T> {
- fn clone(&self) -> Temporary<T> {
- Temporary {
- inner: self.inner,
- _js_ptr: self._js_ptr,
- }
- }
-}
-
-impl<T> PartialEq for Temporary<T> {
- fn eq(&self, other: &Temporary<T>) -> bool {
- self.inner == other.inner
- }
-}
-
-impl<T: Reflectable> Temporary<T> {
- /// Create a new `Temporary` value from an unrooted value.
- #[allow(unrooted_must_root)]
- pub fn from_unrooted(unrooted: Unrooted<T>) -> Temporary<T> {
- Temporary {
- inner: JS { ptr: unrooted.ptr },
- _js_ptr: unrooted.reflector().get_jsobject(),
- }
- }
-
- /// Create a new `Temporary` value from a rooted value.
- #[allow(unrooted_must_root)]
- pub fn from_rooted<U: Assignable<T>>(root: U) -> Temporary<T> {
- let inner = JS::from_rooted(root);
- Temporary {
- inner: inner,
- _js_ptr: inner.reflector().get_jsobject(),
- }
- }
-}
-
-impl<T: Reflectable> Rootable<T> for Temporary<T> {
- /// Create a stack-bounded root for this value.
- fn root(&self) -> Root<T> {
- self.inner.root()
- }
-}
-
/// A traced reference to a DOM object. Must only be used as a field in other
/// DOM objects.
#[must_root]
@@ -198,6 +52,32 @@ impl<T> JS<T> {
}
}
}
+impl<T: Reflectable> JS<T> {
+ /// Root this JS-owned value to prevent its collection as garbage.
+ pub fn root(&self) -> Root<T> {
+ Root::new(self.ptr)
+ }
+ /// Create a JS<T> from a Root<T>
+ /// XXX Not a great API. Should be a call on Root<T> instead
+ pub fn from_rooted(root: &Root<T>) -> JS<T> {
+ JS {
+ ptr: unsafe { NonZero::new(&**root) }
+ }
+ }
+ /// Create a JS<T> from a &T
+ pub fn from_ref(obj: &T) -> JS<T> {
+ JS {
+ ptr: unsafe { NonZero::new(&*obj) }
+ }
+ }
+ /// Store an rooted value in this field. This is safe under the
+ /// assumption that JS<T> 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: Root<T>) {
+ self.ptr = val.ptr.clone();
+ }
+}
/// An unrooted reference to a DOM object for use in layout. `Layout*Helpers`
/// traits must be implemented on this.
@@ -208,7 +88,7 @@ pub struct LayoutJS<T> {
impl<T: Reflectable> LayoutJS<T> {
/// Get the reflector.
pub unsafe fn get_jsobject(&self) -> *mut JSObject {
- (**self.ptr).reflector().get_jsobject()
+ (**self.ptr).reflector().get_jsobject().get()
}
}
@@ -217,14 +97,12 @@ impl<T> Copy for JS<T> {}
impl<T> Copy for LayoutJS<T> {}
impl<T> PartialEq for JS<T> {
- #[allow(unrooted_must_root)]
fn eq(&self, other: &JS<T>) -> bool {
self.ptr == other.ptr
}
}
impl<T> PartialEq for LayoutJS<T> {
- #[allow(unrooted_must_root)]
fn eq(&self, other: &LayoutJS<T>) -> bool {
self.ptr == other.ptr
}
@@ -260,29 +138,6 @@ impl LayoutJS<Node> {
}
}
-impl<T: Reflectable> Rootable<T> for JS<T> {
- /// Root this JS-owned value to prevent its collection as garbage.
- fn root(&self) -> Root<T> {
- STACK_ROOTS.with(|ref collection| {
- let RootCollectionPtr(collection) = collection.get().unwrap();
- unsafe {
- Root::new(&*collection, self.ptr)
- }
- })
- }
-}
-
-impl<U: Reflectable> JS<U> {
- /// Create a `JS<T>` from any JS-managed pointer.
- pub fn from_rooted<T: Assignable<U>>(root: T) -> JS<U> {
- unsafe {
- root.get_js()
- }
- }
-}
-
-//XXXjdm This is disappointing. This only gets called from trace hooks, in theory,
-// so it's safe to assume that self is rooted and thereby safe to access.
impl<T: Reflectable> Reflectable for JS<T> {
fn reflector<'a>(&'a self) -> &'a Reflector {
unsafe {
@@ -298,19 +153,50 @@ impl<T: Reflectable> Reflectable for JS<T> {
pub trait HeapGCValue: JSTraceable {
}
-impl HeapGCValue for JSVal {
+impl HeapGCValue for Heap<JSVal> {
}
impl<T: Reflectable> HeapGCValue for JS<T> {
}
-/// A holder that provides interior mutability for GC-managed values such as
-/// `JSVal` and `JS<T>`.
+/// A holder that provides interior mutability for GC-managed JSVals.
///
/// Must be used in place of traditional interior mutability to ensure proper
/// GC barriers are enforced.
#[must_root]
#[jstraceable]
+pub struct MutHeapJSVal {
+ val: UnsafeCell<Heap<JSVal>>,
+}
+
+impl MutHeapJSVal {
+ /// Create a new `MutHeapJSVal`.
+ pub fn new() -> MutHeapJSVal {
+ MutHeapJSVal {
+ val: UnsafeCell::new(Heap::default()),
+ }
+ }
+
+ /// Set this `MutHeapJSVal` to the given value, calling write barriers as
+ /// appropriate.
+ pub fn set(&self, val: JSVal) {
+ unsafe {
+ let cell = self.val.get();
+ (*cell).set(val);
+ }
+ }
+
+ /// Set the value in this `MutHeapJSVal`, calling read barriers as appropriate.
+ pub fn get(&self) -> JSVal {
+ unsafe { (*self.val.get()).get() }
+ }
+}
+
+
+/// A holder that provides interior mutability for GC-managed values such as
+/// `JS<T>`.
+#[must_root]
+#[jstraceable]
pub struct MutHeap<T: HeapGCValue+Copy> {
val: Cell<T>,
}
@@ -323,13 +209,12 @@ impl<T: HeapGCValue+Copy> MutHeap<T> {
}
}
- /// Set this `MutHeap` to the given value, calling write barriers as
- /// appropriate.
+ /// Set this `MutHeap` to the given value.
pub fn set(&self, val: T) {
self.val.set(val)
}
- /// Set the value in this `MutHeap`, calling read barriers as appropriate.
+ /// Set the value in this `MutHeap`.
pub fn get(&self) -> T {
self.val.get()
}
@@ -353,8 +238,7 @@ impl<T: HeapGCValue+Copy> MutNullableHeap<T> {
}
}
- /// Set this `MutNullableHeap` to the given value, calling write barriers
- /// as appropriate.
+ /// Set this `MutNullableHeap` to the given value.
pub fn set(&self, val: Option<T>) {
self.ptr.set(val);
}
@@ -368,14 +252,14 @@ impl<T: HeapGCValue+Copy> MutNullableHeap<T> {
impl<T: Reflectable> MutNullableHeap<JS<T>> {
/// Retrieve a copy of the current inner value. If it is `None`, it is
/// initialized with the result of `cb` first.
- pub fn or_init<F>(&self, cb: F) -> Temporary<T>
- where F: FnOnce() -> Temporary<T>
+ pub fn or_init<F>(&self, cb: F) -> Root<T>
+ where F: FnOnce() -> Root<T>
{
match self.get() {
- Some(inner) => Temporary::from_rooted(inner),
+ Some(inner) => Root::from_rooted(inner),
None => {
let inner = cb();
- self.set(Some(JS::from_rooted(inner.clone())));
+ self.set(Some(JS::from_rooted(&inner)));
inner
},
}
@@ -396,16 +280,6 @@ impl<T: HeapGCValue+Copy> Default for MutNullableHeap<T> {
}
}
-impl<T: Reflectable> JS<T> {
- /// Store an unrooted value in this field. This is safe under the
- /// assumption that JS<T> 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<T>) {
- *self = val.inner.clone();
- }
-}
-
impl<T: Reflectable> LayoutJS<T> {
/// Returns an unsafe pointer to the interior of this JS object. This is
/// the only method that be safely accessed from layout. (The fact that
@@ -419,129 +293,36 @@ impl<T: Reflectable> LayoutJS<T> {
pub trait RootedReference<T> {
/// Obtain a safe optional reference to the wrapped JS owned-value that
/// cannot outlive the lifetime of this root.
- fn r<'a>(&'a self) -> Option<JSRef<'a, T>>;
+ fn r<'a>(&'a self) -> Option<&'a T>;
}
impl<T: Reflectable> RootedReference<T> for Option<Root<T>> {
- fn r<'a>(&'a self) -> Option<JSRef<'a, T>> {
+ fn r<'a>(&'a self) -> Option<&'a T> {
self.as_ref().map(|root| root.r())
}
}
-/// Get an `Option<Option<JSRef<T>>>` out of an `Option<Option<Root<T>>>`
+/// Get an `Option<Option<&T>>` out of an `Option<Option<Root<T>>>`
pub trait OptionalRootedReference<T> {
/// Obtain a safe optional optional reference to the wrapped JS owned-value
/// that cannot outlive the lifetime of this root.
- fn r<'a>(&'a self) -> Option<Option<JSRef<'a, T>>>;
+ fn r<'a>(&'a self) -> Option<Option<&'a T>>;
}
impl<T: Reflectable> OptionalRootedReference<T> for Option<Option<Root<T>>> {
- fn r<'a>(&'a self) -> Option<Option<JSRef<'a, T>>> {
+ fn r<'a>(&'a self) -> Option<Option<&'a T>> {
self.as_ref().map(|inner| inner.r())
}
}
-/// Trait that allows extracting a `JS<T>` 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.
-pub trait Assignable<T> {
- /// Extract an unrooted `JS<T>`.
- unsafe fn get_js(&self) -> JS<T>;
-}
-
-impl<T> Assignable<T> for JS<T> {
- unsafe fn get_js(&self) -> JS<T> {
- self.clone()
- }
-}
-
-impl<'a, T: Reflectable> Assignable<T> for JSRef<'a, T> {
- unsafe fn get_js(&self) -> JS<T> {
- JS {
- ptr: self.ptr
- }
- }
-}
-
-impl<T: Reflectable> Assignable<T> for Temporary<T> {
- unsafe fn get_js(&self) -> JS<T> {
- self.inner.clone()
- }
-}
-
-
-/// Root a rootable `Option` type (used for `Option<Temporary<T>>`)
-pub trait OptionalRootable<T> {
- /// Root the inner value, if it exists.
- fn root(&self) -> Option<Root<T>>;
-}
-
-impl<T: Reflectable, U: Rootable<T>> OptionalRootable<T> for Option<U> {
- fn root(&self) -> Option<Root<T>> {
- self.as_ref().map(|inner| inner.root())
- }
-}
-
-/// Root a rootable `Option<Option>` type (used for `Option<Option<JS<T>>>`)
-pub trait OptionalOptionalRootable<T> {
- /// Root the inner value, if it exists.
- fn root(&self) -> Option<Option<Root<T>>>;
-}
-
-impl<T: Reflectable, U: OptionalRootable<T>> OptionalOptionalRootable<T> for Option<U> {
- fn root(&self) -> Option<Option<Root<T>>> {
- self.as_ref().map(|inner| inner.root())
- }
-}
-
-/// Root a rootable `Result` type (any of `Temporary<T>` or `JS<T>`)
-pub trait ResultRootable<T,U> {
- /// Root the inner value, if it exists.
- fn root(self) -> Result<Root<T>, U>;
-}
-
-impl<T: Reflectable, U, V: Rootable<T>> ResultRootable<T, U> for Result<V, U> {
- fn root(self) -> Result<Root<T>, U> {
- self.map(|inner| inner.root())
- }
-}
-
-/// Root a rootable type.
-pub trait Rootable<T> {
- /// Root the value.
- fn root(&self) -> Root<T>;
-}
-
-
-/// Provides a facility to push unrooted values onto lists of rooted values.
-/// This is safe under the assumption that said lists are reachable via the GC
-/// graph, and therefore the new values are transitively rooted for the
-/// lifetime of their new owner.
-pub trait TemporaryPushable<T> {
- /// Push a new value onto this container.
- fn push_unrooted(&mut self, val: &T);
- /// Insert a new value into this container.
- fn insert_unrooted(&mut self, index: usize, val: &T);
-}
-
-impl<T: Assignable<U>, U: Reflectable> TemporaryPushable<T> for Vec<JS<U>> {
- fn push_unrooted(&mut self, val: &T) {
- self.push(unsafe { val.get_js() });
- }
-
- fn insert_unrooted(&mut self, index: usize, val: &T) {
- self.insert(index, unsafe { val.get_js() });
- }
-}
-
-/// An opaque, LIFO rooting mechanism. This tracks roots and ensures that they
-/// are destructed in a LIFO order.
+/// A rooting mechanism for reflectors on the stack.
+/// LIFO is not required.
///
/// See also [*Exact Stack Rooting - Storing a GCPointer on the CStack*]
/// (https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/GC/Exact_Stack_Rooting).
#[no_move]
pub struct RootCollection {
- roots: UnsafeCell<RootedVec<*mut JSObject>>,
+ roots: UnsafeCell<Vec<*const Reflector>>,
}
/// A pointer to a RootCollection, for use in global variables.
@@ -555,142 +336,114 @@ impl Clone for RootCollectionPtr {
impl RootCollection {
/// Create an empty collection of roots
pub fn new() -> RootCollection {
- let addr = unsafe {
- return_address() as *const libc::c_void
- };
-
RootCollection {
- roots: UnsafeCell::new(RootedVec::new_with_destination_address(addr)),
+ roots: UnsafeCell::new(vec!()),
}
}
- /// Track a stack-based root as a pointer to ensure LIFO root ordering.
- fn root<'b>(&self, untracked_js_ptr: *mut JSObject) {
+ /// Start tracking a stack-based root
+ fn root<'b>(&self, untracked_reflector: *const Reflector) {
unsafe {
- let roots = self.roots.get();
- (*roots).push(untracked_js_ptr);
- debug!(" rooting {:?}", untracked_js_ptr);
+ let mut roots = &mut *self.roots.get();
+ roots.push(untracked_reflector);
+ assert!(!(*untracked_reflector).get_jsobject().is_null())
}
}
- /// Stop tracking a stack-based root, asserting if LIFO root ordering has
- /// been violated
+ /// Stop tracking a stack-based root, asserting if the reflector isn't found
fn unroot<'b, T: Reflectable>(&self, rooted: &Root<T>) {
unsafe {
- let roots = self.roots.get();
- let unrooted = (*roots).pop().unwrap();
- debug!("unrooted {:?} (expecting {:?}", unrooted, rooted.js_ptr);
- assert!(unrooted == rooted.js_ptr);
+ let mut roots = &mut *self.roots.get();
+ let old_reflector = &*rooted.r().reflector();
+ match roots.iter().rposition(|r| *r == old_reflector) {
+ Some(idx) => {
+ roots.remove(idx);
+ },
+ None => panic!("Can't remove a root that was never rooted!")
+ }
}
}
}
+/// SM Callback that traces the rooted reflectors
+pub unsafe fn trace_roots(tracer: *mut JSTracer) {
+ STACK_ROOTS.with(|ref collection| {
+ let RootCollectionPtr(collection) = collection.get().unwrap();
+ let collection = &*(*collection).roots.get();
+ for root in collection.iter() {
+ trace_reflector(tracer, "reflector", &**root);
+ }
+ });
+}
+
/// A rooted reference to a DOM object.
///
/// The JS value is pinned for the duration of this object's lifetime; roots
/// are additive, so this object's destruction will not invalidate other roots
/// for the same JS value. `Root`s cannot outlive the associated
-/// `RootCollection` object. Attempts to transfer ownership of a `Root` via
-/// moving will trigger dynamic unrooting failures due to incorrect ordering.
-#[no_move]
+/// `RootCollection` object.
pub struct Root<T: Reflectable> {
- /// List that ensures correct dynamic root ordering
- root_list: &'static RootCollection,
/// Reference to rooted value that must not outlive this container
ptr: NonZero<*const T>,
- /// On-stack JS pointer to assuage conservative stack scanner
- js_ptr: *mut JSObject,
+ /// List that ensures correct dynamic root ordering
+ root_list: *const RootCollection,
}
impl<T: Reflectable> Root<T> {
/// Create a new stack-bounded root for the provided JS-owned value.
- /// It cannot not outlive its associated `RootCollection`, and it contains
- /// a `JSRef` which cannot outlive this new `Root`.
- #[inline]
- fn new(roots: &'static RootCollection, unrooted: NonZero<*const T>)
- -> Root<T> {
- let js_ptr = unsafe {
- (**unrooted).reflector().get_jsobject()
- };
- roots.root(js_ptr);
- Root {
- root_list: roots,
- ptr: unrooted,
- js_ptr: js_ptr,
- }
+ /// It cannot not outlive its associated `RootCollection`, and it gives
+ /// out references which cannot outlive this new `Root`.
+ pub fn new(unrooted: NonZero<*const T>)
+ -> Root<T> {
+ STACK_ROOTS.with(|ref collection| {
+ let RootCollectionPtr(collection) = collection.get().unwrap();
+ unsafe { (*collection).root(&*(**unrooted).reflector()) }
+ Root {
+ ptr: unrooted,
+ root_list: collection,
+ }
+ })
}
- /// Obtain a safe reference to the wrapped JS owned-value that cannot
- /// outlive the lifetime of this root.
- pub fn r<'b>(&'b self) -> JSRef<'b, T> {
- JSRef {
- ptr: self.ptr,
- chain: PhantomData,
- }
+ /// Generate a new root from a reference
+ pub fn from_ref(unrooted: &T) -> Root<T> {
+ Root::new(unsafe { NonZero::new(&*unrooted) })
}
- /// Obtain an unsafe reference to the wrapped JS owned-value that can
+ /// Obtain a safe reference to the wrapped JS owned-value that cannot
/// outlive the lifetime of this root.
- ///
- /// DO NOT CALL.
- pub fn get_unsound_ref_forever<'b>(&self) -> JSRef<'b, T> {
- JSRef {
- ptr: self.ptr,
- chain: PhantomData,
- }
+ pub fn r<'a>(&'a self) -> &'a T {
+ &**self
}
-}
-impl<T: Reflectable> Drop for Root<T> {
- fn drop(&mut self) {
- self.root_list.unroot(self);
+ /// Don't use this. Don't make me find you.
+ pub fn get_unsound_ref_forever<'a, 'b>(&'a self) -> &'b T {
+ unsafe { &**self.ptr }
}
-}
-impl<'a, T: Reflectable> Deref for JSRef<'a, T> {
- type Target = T;
- fn deref<'b>(&'b self) -> &'b T {
- unsafe {
- &**self.ptr
- }
+ /// Generate a new root from a JS<T> reference
+ #[allow(unrooted_must_root)]
+ pub fn from_rooted(js: JS<T>) -> Root<T> {
+ js.root()
}
}
-/// A reference to a DOM object that is guaranteed to be alive. This is freely
-/// copyable.
-pub struct JSRef<'a, T> {
- ptr: NonZero<*const T>,
- chain: PhantomData<&'a ()>,
-}
-
-impl<'a, T> Copy for JSRef<'a, T> {}
-
-impl<'a, T> Clone for JSRef<'a, T> {
- fn clone(&self) -> JSRef<'a, T> {
- JSRef {
- ptr: self.ptr.clone(),
- chain: self.chain,
- }
+impl<T: Reflectable> Deref for Root<T> {
+ type Target = T;
+ fn deref<'a>(&'a self) -> &'a T {
+ unsafe { &**self.ptr.deref() }
}
}
-impl<'a, 'b, T> PartialEq<JSRef<'b, T>> for JSRef<'a, T> {
- fn eq(&self, other: &JSRef<T>) -> bool {
+impl<T: Reflectable> PartialEq for Root<T> {
+ fn eq(&self, other: &Root<T>) -> bool {
self.ptr == other.ptr
}
}
-impl<'a, T: Reflectable> JSRef<'a, T> {
- /// Returns the inner pointer directly.
- pub fn extended_deref(self) -> &'a T {
- unsafe {
- &**self.ptr
- }
+impl<T: Reflectable> Drop for Root<T> {
+ fn drop(&mut self) {
+ unsafe { (*self.root_list).unroot(self); }
}
}
-impl<'a, T: Reflectable> Reflectable for JSRef<'a, T> {
- fn reflector<'b>(&'b self) -> &'b Reflector {
- (**self).reflector()
- }
-}
diff --git a/components/script/dom/bindings/proxyhandler.rs b/components/script/dom/bindings/proxyhandler.rs
index 4441bdf2335..b7800ddc83e 100644
--- a/components/script/dom/bindings/proxyhandler.rs
+++ b/components/script/dom/bindings/proxyhandler.rs
@@ -8,18 +8,19 @@
use dom::bindings::conversions::is_dom_proxy;
use dom::bindings::utils::delete_property_by_id;
-use js::jsapi::{JSContext, jsid, JSPropertyDescriptor, JSObject, JSString};
+use js::jsapi::{JSContext, JSPropertyDescriptor, JSObject, JSString};
use js::jsapi::{JS_GetPropertyDescriptorById, JS_NewStringCopyN};
-use js::jsapi::{JS_DefinePropertyById, JS_NewObjectWithGivenProto};
-use js::jsapi::{JS_ReportErrorFlagsAndNumber, JS_StrictPropertyStub};
-use js::jsapi::{JSREPORT_WARNING, JSREPORT_STRICT, JSREPORT_STRICT_MODE_ERROR};
+use js::jsapi::{JS_DefinePropertyById6, JS_NewObjectWithGivenProto};
+use js::jsapi::{JS_StrictPropertyStub, JSErrNum};
+use js::jsapi::{Handle, HandleObject, HandleId, MutableHandle, RootedObject, ObjectOpResult};
+use js::jsapi::AutoIdVector;
+use js::jsapi::GetObjectProto;
use js::jsval::ObjectValue;
use js::glue::GetProxyExtra;
-use js::glue::{GetObjectProto, GetObjectParent, SetProxyExtra, GetProxyHandler};
+use js::glue::{SetProxyExtra, GetProxyHandler};
use js::glue::InvokeGetOwnPropertyDescriptor;
-use js::glue::RUST_js_GetErrorMessage;
-use js::glue::AutoIdVector;
-use js::{JSPROP_GETTER, JSPROP_ENUMERATE, JSPROP_READONLY, JSRESOLVE_QUALIFIED};
+use js::{JSPROP_GETTER, JSPROP_ENUMERATE, JSPROP_READONLY};
+use js::{JSTrue, JSFalse};
use libc;
use std::mem;
@@ -32,60 +33,78 @@ static JSPROXYSLOT_EXPANDO: u32 = 0;
/// Otherwise, walk along the prototype chain to find a property with that
/// name.
pub unsafe extern fn get_property_descriptor(cx: *mut JSContext,
- proxy: *mut JSObject,
- id: jsid, set: bool,
- desc: *mut JSPropertyDescriptor)
- -> bool {
- let handler = GetProxyHandler(proxy);
- if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, set, desc) {
- return false;
+ proxy: HandleObject,
+ id: HandleId,
+ desc: MutableHandle<JSPropertyDescriptor>)
+ -> u8 {
+ let handler = GetProxyHandler(proxy.get());
+ if InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, desc) == 0 {
+ return JSFalse;
}
- if !(*desc).obj.is_null() {
- return true;
+ if !desc.get().obj.is_null() {
+ return JSTrue;
}
- //let proto = JS_GetPrototype(proxy);
- let proto = GetObjectProto(proxy);
- if proto.is_null() {
- (*desc).obj = ptr::null_mut();
- return true;
+ let mut proto = RootedObject::new(cx, ptr::null_mut());
+ if GetObjectProto(cx, proxy, proto.handle_mut()) == 0 {
+ desc.get().obj = ptr::null_mut();
+ return JSTrue;
}
- JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc) != 0
+ JS_GetPropertyDescriptorById(cx, proto.handle(), id, desc)
}
/// Defines an expando on the given `proxy`.
-pub unsafe extern fn define_property(cx: *mut JSContext, proxy: *mut JSObject,
- id: jsid, desc: *mut JSPropertyDescriptor)
- -> bool {
- static JSMSG_GETTER_ONLY: libc::c_uint = 160;
-
+pub unsafe extern fn define_property(cx: *mut JSContext, proxy: HandleObject,
+ id: HandleId, desc: Handle<JSPropertyDescriptor>,
+ result: *mut ObjectOpResult)
+ -> u8 {
//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.get().setter);
let setter_stub: *const libc::c_void = mem::transmute(JS_StrictPropertyStub);
- 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;
+ if (desc.get().attrs & JSPROP_GETTER) != 0 && setter == setter_stub {
+ (*result).code_ = JSErrNum::JSMSG_GETTER_ONLY as u32;
+ return JSTrue;
}
- let expando = ensure_expando_object(cx, proxy);
- return JS_DefinePropertyById(cx, expando, id, (*desc).value, (*desc).getter,
- (*desc).setter, (*desc).attrs) != 0;
+ let expando = RootedObject::new(cx, ensure_expando_object(cx, proxy));
+ JS_DefinePropertyById6(cx, expando.handle(), id, desc, result)
}
/// Deletes an expando off the given `proxy`.
-pub unsafe extern fn delete(cx: *mut JSContext, proxy: *mut JSObject, id: jsid,
- bp: *mut bool) -> bool {
- let expando = get_expando_object(proxy);
- if expando.is_null() {
- *bp = true;
- return true;
+pub unsafe extern fn delete(cx: *mut JSContext, proxy: HandleObject, id: HandleId,
+ bp: *mut ObjectOpResult) -> u8 {
+ let expando = RootedObject::new(cx, get_expando_object(proxy));
+ if expando.ptr.is_null() {
+ (*bp).code_ = 0 /* OkCode */;
+ return JSTrue;
}
- return delete_property_by_id(cx, expando, id, &mut *bp);
+ delete_property_by_id(cx, expando.handle(), id, bp)
+}
+
+/// Stub for ownPropertyKeys
+pub unsafe extern fn own_property_keys(cx: *mut JSContext,
+ proxy: HandleObject,
+ props: *mut AutoIdVector) -> u8 {
+ // FIXME: implement this
+ // https://github.com/servo/servo/issues/6390
+ JSTrue
+}
+
+/// Controls whether the Extensible bit can be changed
+pub unsafe extern fn prevent_extensions(_cx: *mut JSContext,
+ _proxy: HandleObject,
+ result: *mut ObjectOpResult) -> u8 {
+ (*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as u32;
+ return JSTrue;
+}
+
+/// Reports whether the object is Extensible
+pub unsafe extern fn is_extensible(_cx: *mut JSContext, _proxy: HandleObject,
+ succeeded: *mut u8) -> u8 {
+ *succeeded = JSTrue;
+ return JSTrue;
}
/// Returns the stringification of an object with class `name`.
@@ -103,10 +122,10 @@ pub fn object_to_string(cx: *mut JSContext, name: &str) -> *mut JSString {
}
/// Get the expando object, or null if there is none.
-pub fn get_expando_object(obj: *mut JSObject) -> *mut JSObject {
+pub fn get_expando_object(obj: HandleObject) -> *mut JSObject {
unsafe {
- assert!(is_dom_proxy(obj));
- let val = GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
+ assert!(is_dom_proxy(obj.get()));
+ let val = GetProxyExtra(obj.get(), JSPROXYSLOT_EXPANDO);
if val.is_undefined() {
ptr::null_mut()
} else {
@@ -117,18 +136,16 @@ pub fn get_expando_object(obj: *mut JSObject) -> *mut JSObject {
/// Get the expando object, or create it if it doesn't exist yet.
/// Fails on JSAPI failure.
-pub fn ensure_expando_object(cx: *mut JSContext, obj: *mut JSObject)
+pub fn ensure_expando_object(cx: *mut JSContext, obj: HandleObject)
-> *mut JSObject {
unsafe {
- assert!(is_dom_proxy(obj));
+ assert!(is_dom_proxy(obj.get()));
let mut expando = get_expando_object(obj);
if expando.is_null() {
- expando = JS_NewObjectWithGivenProto(cx, ptr::null_mut(),
- ptr::null_mut(),
- GetObjectParent(obj));
+ expando = JS_NewObjectWithGivenProto(cx, ptr::null_mut(), HandleObject::null());
assert!(!expando.is_null());
- SetProxyExtra(obj, JSPROXYSLOT_EXPANDO, ObjectValue(&*expando));
+ SetProxyExtra(obj.get(), JSPROXYSLOT_EXPANDO, ObjectValue(&*expando));
}
return expando;
}
@@ -142,18 +159,4 @@ pub fn fill_property_descriptor(desc: &mut JSPropertyDescriptor,
desc.attrs = if readonly { JSPROP_READONLY } else { 0 } | JSPROP_ENUMERATE;
desc.getter = None;
desc.setter = None;
- desc.shortid = 0;
-}
-
-/// No-op required hook.
-pub unsafe extern fn get_own_property_names(_cx: *mut JSContext,
- _obj: *mut JSObject,
- _v: *mut AutoIdVector) -> bool {
- true
-}
-
-/// No-op required hook.
-pub unsafe extern fn enumerate(_cx: *mut JSContext, _obj: *mut JSObject,
- _v: *mut AutoIdVector) -> bool {
- true
}
diff --git a/components/script/dom/bindings/refcounted.rs b/components/script/dom/bindings/refcounted.rs
index 046ae913b50..ad7f9239eae 100644
--- a/components/script/dom/bindings/refcounted.rs
+++ b/components/script/dom/bindings/refcounted.rs
@@ -22,11 +22,12 @@
//! is rooted when a hashmap entry is first created, and unrooted when the hashmap entry
//! is removed.
-use dom::bindings::js::{Temporary, JSRef, Unrooted};
+use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, Reflectable};
+use dom::bindings::trace::trace_reflector;
use script_task::{ScriptMsg, ScriptChan};
-use js::jsapi::{JS_AddObjectRoot, JS_RemoveObjectRoot, JSContext};
+use js::jsapi::{JSContext, JSTracer};
use libc;
use std::cell::RefCell;
@@ -35,6 +36,7 @@ use std::collections::hash_map::Entry::{Vacant, Occupied};
use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
+use core::nonzero::NonZero;
thread_local!(pub static LIVE_REFERENCES: Rc<RefCell<Option<LiveDOMReferences>>> = Rc::new(RefCell::new(None)));
@@ -63,7 +65,7 @@ impl<T: Reflectable> Trusted<T> {
/// Create a new `Trusted<T>` instance from an existing DOM pointer. The DOM object will
/// be prevented from being GCed for the duration of the resulting `Trusted<T>` object's
/// lifetime.
- pub fn new(cx: *mut JSContext, ptr: JSRef<T>, script_chan: Box<ScriptChan + Send>) -> Trusted<T> {
+ pub fn new(cx: *mut JSContext, ptr: &T, script_chan: Box<ScriptChan + Send>) -> Trusted<T> {
LIVE_REFERENCES.with(|ref r| {
let r = r.borrow();
let live_references = r.as_ref().unwrap();
@@ -81,14 +83,14 @@ impl<T: Reflectable> Trusted<T> {
/// Obtain a usable DOM pointer from a pinned `Trusted<T>` value. Fails if used on
/// a different thread than the original value from which this `Trusted<T>` was
/// obtained.
- pub fn to_temporary(&self) -> Temporary<T> {
+ pub fn root(&self) -> Root<T> {
assert!(LIVE_REFERENCES.with(|ref r| {
let r = r.borrow();
let live_references = r.as_ref().unwrap();
self.owner_thread == (&*live_references) as *const _ as *const libc::c_void
}));
unsafe {
- Temporary::from_unrooted(Unrooted::from_raw(self.ptr as *const T))
+ Root::new(NonZero::new(self.ptr as *const T))
}
}
}
@@ -151,10 +153,6 @@ impl LiveDOMReferences {
refcount.clone()
}
Vacant(entry) => {
- unsafe {
- let rootable = (*ptr).reflector().rootable();
- JS_AddObjectRoot(cx, rootable);
- }
let refcount = Arc::new(Mutex::new(1));
entry.insert(refcount.clone());
refcount
@@ -168,7 +166,6 @@ impl LiveDOMReferences {
LIVE_REFERENCES.with(|ref r| {
let r = r.borrow();
let live_references = r.as_ref().unwrap();
- let reflectable = raw_reflectable as *const Reflector;
let mut table = live_references.table.borrow_mut();
match table.entry(raw_reflectable) {
Occupied(entry) => {
@@ -178,9 +175,6 @@ impl LiveDOMReferences {
return;
}
- unsafe {
- JS_RemoveObjectRoot(cx, (*reflectable).rootable());
- }
let _ = entry.remove();
}
Vacant(_) => {
@@ -194,3 +188,16 @@ impl LiveDOMReferences {
})
}
}
+
+/// A JSTraceDataOp for tracing reflectors held in LIVE_REFERENCES
+pub unsafe extern fn trace_refcounted_objects(tracer: *mut JSTracer, _data: *mut libc::c_void) {
+ LIVE_REFERENCES.with(|ref r| {
+ let r = r.borrow();
+ let live_references = r.as_ref().unwrap();
+ let table = live_references.table.borrow();
+ for obj in table.keys() {
+ let reflectable = &*(*obj as *const Reflector);
+ trace_reflector(tracer, "LIVE_REFERENCES", reflectable);
+ }
+ });
+}
diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs
index bdcdc140028..5697c7eb7dc 100644
--- a/components/script/dom/bindings/structuredclone.rs
+++ b/components/script/dom/bindings/structuredclone.rs
@@ -13,7 +13,7 @@ use js::glue::JS_STRUCTURED_CLONE_VERSION;
use js::jsapi::JSContext;
use js::jsapi::{JS_WriteStructuredClone, JS_ClearPendingException};
use js::jsapi::JS_ReadStructuredClone;
-use js::jsval::{JSVal, UndefinedValue};
+use js::jsapi::{HandleValue, MutableHandleValue};
use libc::size_t;
use std::ptr;
@@ -26,13 +26,14 @@ pub struct StructuredCloneData {
impl StructuredCloneData {
/// Writes a structured clone. Returns a `DataClone` error if that fails.
- pub fn write(cx: *mut JSContext, message: JSVal)
+ pub fn write(cx: *mut JSContext, message: HandleValue)
-> Fallible<StructuredCloneData> {
let mut data = ptr::null_mut();
let mut nbytes = 0;
let result = unsafe {
JS_WriteStructuredClone(cx, message, &mut data, &mut nbytes,
- ptr::null(), ptr::null_mut())
+ ptr::null(), ptr::null_mut(),
+ HandleValue::undefined())
};
if result == 0 {
unsafe { JS_ClearPendingException(cx); }
@@ -47,15 +48,13 @@ impl StructuredCloneData {
/// Reads a structured clone.
///
/// Panics if `JS_ReadStructuredClone` fails.
- pub fn read(self, global: GlobalRef) -> JSVal {
- let mut message = UndefinedValue();
+ pub fn read(self, global: GlobalRef, rval: MutableHandleValue) {
unsafe {
assert!(JS_ReadStructuredClone(
- global.get_cx(), self.data as *const u64, self.nbytes,
- JS_STRUCTURED_CLONE_VERSION, &mut message,
+ global.get_cx(), self.data, self.nbytes,
+ JS_STRUCTURED_CLONE_VERSION, rval,
ptr::null(), ptr::null_mut()) != 0);
}
- message
}
}
diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs
index 6a0f72412de..f401e278498 100644
--- a/components/script/dom/bindings/trace.rs
+++ b/components/script/dom/bindings/trace.rs
@@ -44,7 +44,8 @@ use euclid::size::Size2D;
use html5ever::tree_builder::QuirksMode;
use hyper::header::Headers;
use hyper::method::Method;
-use js::jsapi::{JSObject, JSTracer, JS_CallTracer, JSGCTraceKind};
+use js::jsapi::{JSObject, JSTracer, JSGCTraceKind, JS_CallValueTracer, JS_CallObjectTracer, GCTraceKindToAscii, Heap};
+use js::jsapi::JS_CallUnbarrieredObjectTracer;
use js::jsval::JSVal;
use js::rust::Runtime;
use layout_interface::{LayoutRPC, LayoutChan};
@@ -59,7 +60,7 @@ use msg::compositor_msg::ScriptListener;
use msg::constellation_msg::ConstellationChan;
use net_traits::image::base::Image;
use util::str::{LengthOrPercentageOrAuto};
-use std::cell::{Cell, RefCell};
+use std::cell::{Cell, UnsafeCell, RefCell};
use std::collections::{HashMap, HashSet};
use std::collections::hash_state::HashState;
use std::ffi::CString;
@@ -91,36 +92,46 @@ no_jsmanaged_fields!(EncodingRef);
no_jsmanaged_fields!(Reflector);
/// Trace a `JSVal`.
-pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: JSVal) {
- if !val.is_markable() {
- return;
- }
-
+pub fn trace_jsval(tracer: *mut JSTracer, description: &str, val: &Heap<JSVal>) {
unsafe {
+ if !val.get().is_markable() {
+ return;
+ }
+
let name = CString::new(description).unwrap();
- (*tracer).debugPrinter = None;
- (*tracer).debugPrintIndex = !0;
- (*tracer).debugPrintArg = name.as_ptr() as *const libc::c_void;
+ (*tracer).debugPrinter_ = None;
+ (*tracer).debugPrintIndex_ = !0;
+ (*tracer).debugPrintArg_ = name.as_ptr() as *const libc::c_void;
debug!("tracing value {}", description);
- JS_CallTracer(tracer, val.to_gcthing(), val.trace_kind());
+ JS_CallValueTracer(tracer, val.ptr.get() as *mut _,
+ GCTraceKindToAscii(val.get().trace_kind()));
}
}
/// Trace the `JSObject` held by `reflector`.
#[allow(unrooted_must_root)]
pub fn trace_reflector(tracer: *mut JSTracer, description: &str, reflector: &Reflector) {
- trace_object(tracer, description, reflector.get_jsobject())
+ unsafe {
+ let name = CString::new(description).unwrap();
+ (*tracer).debugPrinter_ = None;
+ (*tracer).debugPrintIndex_ = !0;
+ (*tracer).debugPrintArg_ = name.as_ptr() as *const libc::c_void;
+ debug!("tracing reflector {}", description);
+ JS_CallUnbarrieredObjectTracer(tracer, reflector.rootable(),
+ GCTraceKindToAscii(JSGCTraceKind::JSTRACE_OBJECT));
+ }
}
/// Trace a `JSObject`.
-pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: *mut JSObject) {
+pub fn trace_object(tracer: *mut JSTracer, description: &str, obj: &Heap<*mut JSObject>) {
unsafe {
let name = CString::new(description).unwrap();
- (*tracer).debugPrinter = None;
- (*tracer).debugPrintIndex = !0;
- (*tracer).debugPrintArg = name.as_ptr() as *const libc::c_void;
+ (*tracer).debugPrinter_ = None;
+ (*tracer).debugPrintIndex_ = !0;
+ (*tracer).debugPrintArg_ = name.as_ptr() as *const libc::c_void;
debug!("tracing {}", description);
- JS_CallTracer(tracer, obj as *mut libc::c_void, JSGCTraceKind::JSTRACE_OBJECT);
+ JS_CallObjectTracer(tracer, obj.ptr.get() as *mut _,
+ GCTraceKindToAscii(JSGCTraceKind::JSTRACE_OBJECT));
}
}
@@ -168,15 +179,26 @@ impl<T: JSTraceable+Copy> JSTraceable for Cell<T> {
}
}
-impl JSTraceable for *mut JSObject {
+impl<T: JSTraceable> JSTraceable for UnsafeCell<T> {
fn trace(&self, trc: *mut JSTracer) {
- trace_object(trc, "object", *self);
+ unsafe { (*self.get()).trace(trc) }
}
}
-impl JSTraceable for JSVal {
+
+impl JSTraceable for Heap<*mut JSObject> {
fn trace(&self, trc: *mut JSTracer) {
- trace_jsval(trc, "val", *self);
+ if self.get().is_null() {
+ return;
+ }
+ trace_object(trc, "object", self);
+ }
+}
+
+
+impl JSTraceable for Heap<JSVal> {
+ fn trace(&self, trc: *mut JSTracer) {
+ trace_jsval(trc, "val", self);
}
}
@@ -324,115 +346,101 @@ impl JSTraceable for () {
}
}
-/// Holds a set of vectors that need to be rooted
-pub struct RootedCollectionSet {
- set: Vec<HashSet<*const RootedVec<Void>>>
+/// Homemade trait object for JSTraceable things
+struct TraceableInfo {
+ pub ptr: *const libc::c_void,
+ pub trace: fn(obj: *const libc::c_void, tracer: *mut JSTracer)
}
-/// TLV Holds a set of vectors that need to be rooted
-thread_local!(pub static ROOTED_COLLECTIONS: Rc<RefCell<RootedCollectionSet>> =
- Rc::new(RefCell::new(RootedCollectionSet::new())));
-
-/// Type of `RootedVec`
-pub enum CollectionType {
- /// DOM objects
- DOMObjects,
- /// `JSVal`s
- JSVals,
- /// `*mut JSObject`s
- JSObjects,
+/// Holds a set of JSTraceables that need to be rooted
+pub struct RootedTraceableSet {
+ set: Vec<TraceableInfo>
}
+/// TLV Holds a set of JSTraceables that need to be rooted
+thread_local!(pub static ROOTED_TRACEABLES: Rc<RefCell<RootedTraceableSet>> =
+ Rc::new(RefCell::new(RootedTraceableSet::new())));
-impl RootedCollectionSet {
- fn new() -> RootedCollectionSet {
- RootedCollectionSet {
- set: vec!(HashSet::new(), HashSet::new(), HashSet::new())
+impl RootedTraceableSet {
+ fn new() -> RootedTraceableSet {
+ RootedTraceableSet {
+ set: vec!()
}
}
- fn remove<T: VecRootableType>(collection: &RootedVec<T>) {
- ROOTED_COLLECTIONS.with(|ref collections| {
- let type_ = VecRootableType::tag(None::<T>);
- let mut collections = collections.borrow_mut();
- assert!(collections.set[type_ as usize].remove(&(collection as *const _ as *const _)));
+ fn remove<T: JSTraceable>(traceable: &T) {
+ ROOTED_TRACEABLES.with(|ref traceables| {
+ let mut traceables = traceables.borrow_mut();
+ let idx =
+ match traceables.set.iter()
+ .rposition(|x| x.ptr == traceable as *const T as *const _) {
+ Some(idx) => idx,
+ None => unreachable!(),
+ };
+ traceables.set.remove(idx);
});
}
- fn add<T: VecRootableType>(collection: &RootedVec<T>) {
- ROOTED_COLLECTIONS.with(|ref collections| {
- let type_ = VecRootableType::tag(None::<T>);
- let mut collections = collections.borrow_mut();
- collections.set[type_ as usize].insert(collection as *const _ as *const _);
+ fn add<T: JSTraceable>(traceable: &T) {
+ ROOTED_TRACEABLES.with(|ref traceables| {
+ fn trace<T: JSTraceable>(obj: *const libc::c_void, tracer: *mut JSTracer) {
+ let obj: &T = unsafe { &*(obj as *const T) };
+ obj.trace(tracer);
+ }
+
+ let mut traceables = traceables.borrow_mut();
+ let info = TraceableInfo {
+ ptr: traceable as *const T as *const libc::c_void,
+ trace: trace::<T>,
+ };
+ traceables.set.push(info);
})
}
unsafe fn trace(&self, tracer: *mut JSTracer) {
- fn trace_collection_type<T>(tracer: *mut JSTracer,
- collections: &HashSet<*const RootedVec<Void>>)
- where T: JSTraceable + VecRootableType
- {
- for collection in collections {
- let collection: *const RootedVec<Void> = *collection;
- let collection = collection as *const RootedVec<T>;
- unsafe {
- let _ = (*collection).trace(tracer);
- }
- }
+ for info in self.set.iter() {
+ (info.trace)(info.ptr, tracer);
}
-
- let dom_collections =
- &self.set[CollectionType::DOMObjects as usize] as *const _ as *const HashSet<*const RootedVec<JS<Void>>>;
- for dom_collection in (*dom_collections).iter() {
- for reflector in (**dom_collection).iter() {
- trace_reflector(tracer, "", reflector.reflector());
- }
- }
-
- trace_collection_type::<JSVal>(tracer, &self.set[CollectionType::JSVals as usize]);
- trace_collection_type::<*mut JSObject>(tracer, &self.set[CollectionType::JSObjects as usize]);
}
}
-
-/// Trait implemented by all types that can be used with RootedVec
-pub trait VecRootableType {
- /// Return the type tag used to determine how to trace RootedVec
- fn tag(_a: Option<Self>) -> CollectionType;
-}
-
-impl<T: Reflectable> VecRootableType for JS<T> {
- fn tag(_a: Option<JS<T>>) -> CollectionType { CollectionType::DOMObjects }
+/// Roots any JSTraceable thing
+///
+/// If you have a valid Reflectable, use Root.
+/// If you have GC things like *mut JSObject or JSVal, use jsapi::Rooted.
+/// If you have an arbitrary number of Reflectables to root, use RootedVec<JS<T>>
+/// If you know what you're doing, use this.
+#[jstraceable]
+pub struct RootedTraceable<'a, T: 'a + JSTraceable> {
+ ptr: &'a T
}
-impl VecRootableType for JSVal {
- fn tag(_a: Option<JSVal>) -> CollectionType { CollectionType::JSVals }
-}
-
-impl VecRootableType for *mut JSObject {
- fn tag(_a: Option<*mut JSObject>) -> CollectionType { CollectionType::JSObjects }
-}
-
-enum Void {}
-
-impl VecRootableType for Void {
- fn tag(_a: Option<Void>) -> CollectionType { unreachable!() }
+impl<'a, T: JSTraceable> RootedTraceable<'a, T> {
+ /// Root a JSTraceable thing for the life of this RootedTraceable
+ pub fn new(traceable: &'a T) -> RootedTraceable<'a, T> {
+ RootedTraceableSet::add(traceable);
+ RootedTraceable { ptr: traceable }
+ }
}
-impl Reflectable for Void {
- fn reflector<'a>(&'a self) -> &'a Reflector { unreachable!() }
+impl<'a, T: JSTraceable> Drop for RootedTraceable<'a, T> {
+ fn drop(&mut self) {
+ RootedTraceableSet::remove(self.ptr);
+ }
}
/// A vector of items that are rooted for the lifetime
-/// of this struct
+/// of this struct.
+/// Must be a reflectable
#[allow(unrooted_must_root)]
#[no_move]
-pub struct RootedVec<T: VecRootableType> {
+#[jstraceable]
+pub struct RootedVec<T: JSTraceable + Reflectable> {
v: Vec<T>
}
-impl<T: VecRootableType> RootedVec<T> {
+impl<T: JSTraceable + Reflectable> RootedVec<T> {
/// Create a vector of items of type T that is rooted for
/// the lifetime of this struct
pub fn new() -> RootedVec<T> {
@@ -444,39 +452,38 @@ impl<T: VecRootableType> RootedVec<T> {
}
/// Create a vector of items of type T. This constructor is specific
- /// for RootCollection.
+ /// for RootTraceableSet.
pub fn new_with_destination_address(addr: *const libc::c_void) -> RootedVec<T> {
unsafe {
- RootedCollectionSet::add::<T>(&*(addr as *const _));
+ RootedTraceableSet::add::<RootedVec<T>>(&*(addr as *const _));
}
RootedVec::<T> { v: vec!() }
}
}
-impl<T: VecRootableType> Drop for RootedVec<T> {
+impl<T: JSTraceable + Reflectable> Drop for RootedVec<T> {
fn drop(&mut self) {
- RootedCollectionSet::remove(self);
+ RootedTraceableSet::remove(self);
}
}
-impl<T: VecRootableType> Deref for RootedVec<T> {
+impl<T: JSTraceable + Reflectable> Deref for RootedVec<T> {
type Target = Vec<T>;
fn deref(&self) -> &Vec<T> {
&self.v
}
}
-impl<T: VecRootableType> DerefMut for RootedVec<T> {
+impl<T: JSTraceable + Reflectable> DerefMut for RootedVec<T> {
fn deref_mut(&mut self) -> &mut Vec<T> {
&mut self.v
}
}
-
-/// SM Callback that traces the rooted collections
-pub unsafe fn trace_collections(tracer: *mut JSTracer) {
- ROOTED_COLLECTIONS.with(|ref collections| {
- let collections = collections.borrow();
- collections.trace(tracer);
+/// SM Callback that traces the rooted traceables
+pub unsafe fn trace_traceables(tracer: *mut JSTracer) {
+ ROOTED_TRACEABLES.with(|ref traceables| {
+ let traceables = traceables.borrow();
+ traceables.trace(tracer);
});
}
diff --git a/components/script/dom/bindings/utils.rs b/components/script/dom/bindings/utils.rs
index bee42bbe2d3..fa7204f7dc8 100644
--- a/components/script/dom/bindings/utils.rs
+++ b/components/script/dom/bindings/utils.rs
@@ -6,10 +6,10 @@
use dom::bindings::codegen::PrototypeList;
use dom::bindings::codegen::PrototypeList::MAX_PROTO_CHAIN_LENGTH;
-use dom::bindings::conversions::{native_from_reflector_jsmanaged, is_dom_class};
+use dom::bindings::conversions::{native_from_handleobject, is_dom_class, jsstring_to_str};
use dom::bindings::error::{Error, ErrorResult, Fallible, throw_type_error};
use dom::bindings::global::GlobalRef;
-use dom::bindings::js::{Temporary, Root, Rootable};
+use dom::bindings::js::Root;
use dom::bindings::trace::trace_object;
use dom::browsercontext;
use dom::window;
@@ -19,30 +19,39 @@ use util::str::DOMString;
use libc;
use libc::c_uint;
use std::boxed;
-use std::cell::Cell;
use std::ffi::CString;
use std::ptr;
+use std::cmp::PartialEq;
+use std::default::Default;
+use std::cell::UnsafeCell;
use js::glue::UnwrapObject;
use js::glue::{IsWrapper, RUST_JSID_IS_INT, RUST_JSID_TO_INT};
-use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewFunction};
+use js::jsapi::{JS_AlreadyHasOwnProperty, JS_NewFunction, JSTraceOp};
use js::jsapi::{JS_DefineProperties, JS_ForwardGetPropertyTo};
-use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype, JS_GetStringCharsAndLength};
-use js::jsapi::{JSHandleObject, JSTracer};
+use js::jsapi::{JS_GetClass, JS_LinkConstructorAndPrototype};
+use js::jsapi::{HandleObject, HandleId, HandleValue, MutableHandleValue};
use js::jsapi::JS_GetFunctionObject;
use js::jsapi::{JS_HasPropertyById, JS_GetPrototype};
use js::jsapi::{JS_GetProperty, JS_HasProperty, JS_SetProperty};
-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::{JS_DefineFunctions, JS_DefineProperty, JS_DefineProperty1};
+use js::jsapi::{JS_GetReservedSlot, JS_SetReservedSlot};
+use js::jsapi::{JSContext, JSObject, JSClass, JSTracer};
use js::jsapi::{JSFunctionSpec, JSPropertySpec};
use js::jsapi::{JS_NewGlobalObject, JS_InitStandardClasses};
-use js::jsapi::JS_DeletePropertyById2;
-use js::jsfriendapi::JS_ObjectToOuterObject;
-use js::jsfriendapi::bindgen::JS_NewObjectWithUniqueType;
+use js::jsapi::{OnNewGlobalHookOption, CompartmentOptions};
+use js::jsapi::{JS_FireOnNewGlobalObject, JSVersion};
+use js::jsapi::JS_DeletePropertyById1;
+use js::jsapi::JS_ObjectToOuterObject;
+use js::jsapi::JS_NewObjectWithUniqueType;
+use js::jsapi::{ObjectOpResult, RootedObject, RootedValue, Heap, MutableHandleObject};
+use js::jsapi::PropertyDefinitionBehavior;
+use js::jsapi::JSAutoCompartment;
+use js::jsapi::{DOMCallbacks, JSWrapObjectCallbacks};
use js::jsval::JSVal;
-use js::jsval::{PrivateValue, ObjectValue, NullValue};
-use js::jsval::{Int32Value, UInt32Value, DoubleValue, BooleanValue, UndefinedValue};
-use js::rust::with_compartment;
+use js::jsval::{PrivateValue, NullValue};
+use js::jsval::{Int32Value, UInt32Value, DoubleValue, BooleanValue};
+use js::rust::{GCMethods, ToString};
+use js::glue::{WrapperNew, GetCrossCompartmentWrapper};
use js::{JSPROP_ENUMERATE, JSPROP_READONLY, JSPROP_PERMANENT};
use js::JSFUN_CONSTRUCTOR;
use js;
@@ -145,7 +154,7 @@ unsafe impl Sync for DOMClass {}
#[derive(Copy)]
pub struct DOMJSClass {
/// The actual JSClass.
- pub base: js::Class,
+ pub base: js::jsapi::Class,
/// Associated data for DOM object reflectors.
pub dom_class: DOMClass
}
@@ -181,95 +190,93 @@ unsafe impl Sync for 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) -> u8;
/// Creates the *interface prototype object* (if a `proto_class` is given)
/// and the *interface object* (if a `constructor` is given).
/// Fails on JSAPI failure.
-pub fn do_create_interface_objects(cx: *mut JSContext, global: *mut JSObject,
- receiver: *mut JSObject,
- proto_proto: *mut JSObject,
+pub fn do_create_interface_objects(cx: *mut JSContext,
+ receiver: HandleObject,
+ proto_proto: HandleObject,
proto_class: Option<&'static JSClass>,
constructor: Option<(NonNullJSNative, &'static str, u32)>,
dom_class: *const DOMClass,
- members: &'static NativeProperties)
- -> *mut JSObject {
+ members: &'static NativeProperties,
+ rval: MutableHandleObject) {
+ if let Some(proto_class) = proto_class {
+ create_interface_prototype_object(cx, proto_proto,
+ proto_class, members, rval);
+ }
+
unsafe {
- let proto = match proto_class {
- Some(proto_class) => {
- let proto = create_interface_prototype_object(cx, global, proto_proto,
- proto_class, members);
- JS_SetReservedSlot(proto, DOM_PROTO_INSTANCE_CLASS_SLOT,
- PrivateValue(dom_class as *const libc::c_void));
- proto
- },
- None => ptr::null_mut()
- };
-
- if let Some((native, name, nargs)) = constructor {
- let s = CString::new(name).unwrap();
- create_interface_object(cx, global, receiver,
- native, nargs, proto,
- members, s.as_ptr())
+ if !rval.get().is_null() {
+ JS_SetReservedSlot(rval.get(), DOM_PROTO_INSTANCE_CLASS_SLOT,
+ PrivateValue(dom_class as *const libc::c_void));
}
+ }
- proto
+ if let Some((native, name, nargs)) = constructor {
+ let s = CString::new(name).unwrap();
+ create_interface_object(cx, receiver,
+ native, nargs, rval.handle(),
+ members, s.as_ptr())
}
}
/// Creates the *interface object*.
/// Fails on JSAPI failure.
-fn create_interface_object(cx: *mut JSContext, global: *mut JSObject,
- receiver: *mut JSObject,
+fn create_interface_object(cx: *mut JSContext,
+ receiver: HandleObject,
constructor_native: NonNullJSNative,
- ctor_nargs: u32, proto: *mut JSObject,
+ ctor_nargs: u32, proto: HandleObject,
members: &'static NativeProperties,
name: *const libc::c_char) {
unsafe {
let fun = JS_NewFunction(cx, Some(constructor_native), ctor_nargs,
- JSFUN_CONSTRUCTOR, global, name);
+ JSFUN_CONSTRUCTOR, name);
assert!(!fun.is_null());
- let constructor = JS_GetFunctionObject(fun);
- assert!(!constructor.is_null());
+ let constructor = RootedObject::new(cx, JS_GetFunctionObject(fun));
+ assert!(!constructor.ptr.is_null());
if let Some(static_methods) = members.static_methods {
- define_methods(cx, constructor, static_methods);
+ define_methods(cx, constructor.handle(), static_methods);
}
if let Some(static_properties) = members.static_attrs {
- define_properties(cx, constructor, static_properties);
+ define_properties(cx, constructor.handle(), static_properties);
}
if let Some(constants) = members.consts {
- define_constants(cx, constructor, constants);
+ define_constants(cx, constructor.handle(), constants);
}
- if !proto.is_null() {
- assert!(JS_LinkConstructorAndPrototype(cx, constructor, proto) != 0);
+ if !proto.get().is_null() {
+ assert!(JS_LinkConstructorAndPrototype(cx, constructor.handle(), proto) != 0);
}
let mut already_defined = 0;
assert!(JS_AlreadyHasOwnProperty(cx, receiver, name, &mut already_defined) != 0);
if already_defined == 0 {
- assert!(JS_DefineProperty(cx, receiver, name,
- ObjectValue(&*constructor),
- None, None, 0) != 0);
+ assert!(JS_DefineProperty1(cx, receiver, name,
+ constructor.handle(),
+ 0, None, None) != 0);
}
}
}
/// Defines constants on `obj`.
/// Fails on JSAPI failure.
-fn define_constants(cx: *mut JSContext, obj: *mut JSObject,
+fn define_constants(cx: *mut JSContext, obj: HandleObject,
constants: &'static [ConstantSpec]) {
for spec in constants.iter() {
+ let value = RootedValue::new(cx, spec.get_value());
unsafe {
assert!(JS_DefineProperty(cx, obj, spec.name.as_ptr() as *const libc::c_char,
- spec.get_value(), None, None,
+ value.handle(),
JSPROP_ENUMERATE | JSPROP_READONLY |
- JSPROP_PERMANENT) != 0);
+ JSPROP_PERMANENT, None, None) != 0);
}
}
}
@@ -277,17 +284,17 @@ fn define_constants(cx: *mut JSContext, obj: *mut JSObject,
/// Defines methods on `obj`. The last entry of `methods` must contain zeroed
/// memory.
/// Fails on JSAPI failure.
-fn define_methods(cx: *mut JSContext, obj: *mut JSObject,
+fn define_methods(cx: *mut JSContext, obj: HandleObject,
methods: &'static [JSFunctionSpec]) {
unsafe {
- assert!(JS_DefineFunctions(cx, obj, methods.as_ptr()) != 0);
+ assert!(JS_DefineFunctions(cx, obj, methods.as_ptr(), PropertyDefinitionBehavior::DefineAllProperties) != 0);
}
}
/// Defines attributes on `obj`. The last entry of `properties` must contain
/// zeroed memory.
/// Fails on JSAPI failure.
-fn define_properties(cx: *mut JSContext, obj: *mut JSObject,
+fn define_properties(cx: *mut JSContext, obj: HandleObject,
properties: &'static [JSPropertySpec]) {
unsafe {
assert!(JS_DefineProperties(cx, obj, properties.as_ptr()) != 0);
@@ -296,36 +303,32 @@ fn define_properties(cx: *mut JSContext, obj: *mut JSObject,
/// Creates the *interface prototype object*.
/// Fails on JSAPI failure.
-fn create_interface_prototype_object(cx: *mut JSContext, global: *mut JSObject,
- parent_proto: *mut JSObject,
+fn create_interface_prototype_object(cx: *mut JSContext, global: HandleObject,
proto_class: &'static JSClass,
- members: &'static NativeProperties)
- -> *mut JSObject {
+ members: &'static NativeProperties,
+ rval: MutableHandleObject) {
unsafe {
- let our_proto = JS_NewObjectWithUniqueType(cx, proto_class,
- &*parent_proto, &*global);
- assert!(!our_proto.is_null());
+ rval.set(JS_NewObjectWithUniqueType(cx, proto_class, global));
+ assert!(!rval.get().is_null());
if let Some(methods) = members.methods {
- define_methods(cx, our_proto, methods);
+ define_methods(cx, rval.handle(), methods);
}
if let Some(properties) = members.attrs {
- define_properties(cx, our_proto, properties);
+ define_properties(cx, rval.handle(), properties);
}
if let Some(constants) = members.consts {
- define_constants(cx, our_proto, constants);
+ define_constants(cx, rval.handle(), constants);
}
-
- return our_proto;
}
}
/// A throwing constructor, for those interfaces that have neither
/// `NoInterfaceObject` nor `Constructor`.
pub unsafe extern fn throwing_constructor(cx: *mut JSContext, _argc: c_uint,
- _vp: *mut JSVal) -> JSBool {
+ _vp: *mut JSVal) -> u8 {
throw_type_error(cx, "Illegal constructor.");
return 0;
}
@@ -351,6 +354,10 @@ pub fn initialize_global(global: *mut JSObject) {
pub trait Reflectable {
/// Returns the receiver's reflector.
fn reflector<'a>(&'a self) -> &'a Reflector;
+ /// Initializes the Reflector
+ fn init_reflector(&mut self, _obj: *mut JSObject) {
+ panic!("Cannot call init on this Reflectable");
+ }
}
/// Create the reflector for a new DOM object and yield ownership to the
@@ -358,47 +365,56 @@ pub trait Reflectable {
pub fn reflect_dom_object<T: Reflectable>
(obj: Box<T>,
global: GlobalRef,
- wrap_fn: extern "Rust" fn(*mut JSContext, GlobalRef, Box<T>) -> Temporary<T>)
- -> Temporary<T> {
+ wrap_fn: extern "Rust" fn(*mut JSContext, GlobalRef, Box<T>) -> Root<T>)
+ -> Root<T> {
wrap_fn(global.get_cx(), global, obj)
}
/// A struct to store a reference to the reflector of a DOM object.
// Allowing unused_attribute because the lint sometimes doesn't run in order
#[allow(raw_pointer_derive, unrooted_must_root, unused_attributes)]
-#[derive(PartialEq)]
#[must_root]
#[servo_lang = "reflector"]
// If you're renaming or moving this field, update the path in plugins::reflector as well
pub struct Reflector {
- object: Cell<*mut JSObject>,
+ object: UnsafeCell<*mut JSObject>,
+}
+
+#[allow(unrooted_must_root)]
+impl PartialEq for Reflector {
+ fn eq(&self, other: &Reflector) -> bool {
+ unsafe { *self.object.get() == *other.object.get() }
+ }
}
impl Reflector {
/// Get the reflector.
#[inline]
- pub fn get_jsobject(&self) -> *mut JSObject {
- self.object.get()
+ pub fn get_jsobject(&self) -> HandleObject {
+ HandleObject { ptr: self.object.get() }
}
/// Initialize the reflector. (May be called only once.)
- pub fn set_jsobject(&self, object: *mut JSObject) {
- assert!(self.object.get().is_null());
- assert!(!object.is_null());
- self.object.set(object);
+ pub fn set_jsobject(&mut self, object: *mut JSObject) {
+ unsafe {
+ let obj = self.object.get();
+ assert!((*obj).is_null());
+ assert!(!object.is_null());
+ *obj = object;
+ }
}
/// Return a pointer to the memory location at which the JS reflector
- /// object is stored. Used by Temporary values to root the reflector, as
+ /// object is stored. Used to root the reflector, as
/// required by the JSAPI rooting APIs.
- pub unsafe fn rootable(&self) -> *mut *mut JSObject {
- self.object.as_unsafe_cell().get()
+ pub fn rootable(&self) -> *mut *mut JSObject {
+ self.object.get()
}
/// Create an uninitialized `Reflector`.
pub fn new() -> Reflector {
Reflector {
- object: Cell::new(ptr::null_mut()),
+ object: UnsafeCell::new(ptr::null_mut())
}
}
}
@@ -407,33 +423,34 @@ impl Reflector {
/// set to true and `*vp` to the value, otherwise `*found` is set to false.
///
/// Returns false on JSAPI failure.
-pub fn get_property_on_prototype(cx: *mut JSContext, proxy: *mut JSObject,
- id: jsid, found: *mut bool, vp: *mut JSVal)
+pub fn get_property_on_prototype(cx: *mut JSContext, proxy: HandleObject,
+ id: HandleId, found: *mut bool, vp: MutableHandleValue)
-> bool {
unsafe {
//let proto = GetObjectProto(proxy);
- let proto = JS_GetPrototype(proxy);
- if proto.is_null() {
+ let mut proto = RootedObject::new(cx, ptr::null_mut());
+ if JS_GetPrototype(cx, proxy, proto.handle_mut()) == 0 ||
+ proto.ptr.is_null() {
*found = false;
return true;
}
let mut has_property = 0;
- if JS_HasPropertyById(cx, proto, id, &mut has_property) == 0 {
+ if JS_HasPropertyById(cx, proto.handle(), id, &mut has_property) == 0 {
return false;
}
*found = has_property != 0;
- let no_output = vp.is_null();
+ let no_output = vp.ptr.is_null();
if has_property == 0 || no_output {
return true;
}
- JS_ForwardGetPropertyTo(cx, proto, id, proxy, vp) != 0
+ JS_ForwardGetPropertyTo(cx, proto.handle(), id, proxy, vp) != 0
}
}
/// Get an array index from the given `jsid`. Returns `None` if the given
/// `jsid` is not an integer.
-pub fn get_array_index_from_id(_cx: *mut JSContext, id: jsid) -> Option<u32> {
+pub fn get_array_index_from_id(_cx: *mut JSContext, id: HandleId) -> Option<u32> {
unsafe {
if RUST_JSID_IS_INT(id) != 0 {
return Some(RUST_JSID_TO_INT(id) as u32);
@@ -460,28 +477,16 @@ pub fn get_array_index_from_id(_cx: *mut JSContext, id: jsid) -> Option<u32> {
/// Returns `Err(())` on JSAPI failure (there is a pending exception), and
/// `Ok(None)` if there was no matching string.
pub fn find_enum_string_index(cx: *mut JSContext,
- v: JSVal,
+ v: HandleValue,
values: &[&'static str])
-> Result<Option<usize>, ()> {
- unsafe {
- let jsstr = JS_ValueToString(cx, v);
- if jsstr.is_null() {
- return Err(());
- }
-
- let mut length = 0;
- let chars = JS_GetStringCharsAndLength(cx, jsstr, &mut length);
- if chars.is_null() {
- return Err(());
- }
-
- Ok(values.iter().position(|value| {
- value.len() == length as usize &&
- (0..length as usize).all(|j| {
- value.as_bytes()[j] as u16 == *chars.offset(j as isize)
- })
- }))
+ let jsstr = ToString(cx, v);
+ if jsstr.is_null() {
+ return Err(());
}
+
+ let search = jsstring_to_str(cx, jsstr);
+ Ok(values.iter().position(|value| value == &search))
}
/// Returns wether `obj` is a platform object
@@ -495,7 +500,7 @@ pub fn is_platform_object(obj: *mut JSObject) -> bool {
}
// Now for simplicity check for security wrappers before anything else
if IsWrapper(obj) == 1 {
- let unwrapped_obj = UnwrapObject(obj, /* stopAtOuter = */ 0, ptr::null_mut());
+ let unwrapped_obj = UnwrapObject(obj, /* stopAtOuter = */ 0);
if unwrapped_obj.is_null() {
return false;
}
@@ -508,53 +513,54 @@ pub fn is_platform_object(obj: *mut JSObject) -> bool {
/// Get the property with name `property` from `object`.
/// Returns `Err(())` on JSAPI failure (there is a pending exception), and
-/// `Ok(None)` if there was no property with the given name.
+/// `Ok(false)` if there was no property with the given name.
pub fn get_dictionary_property(cx: *mut JSContext,
- object: *mut JSObject,
- property: &str) -> Result<Option<JSVal>, ()> {
- fn has_property(cx: *mut JSContext, object: *mut JSObject, property: &CString,
- found: &mut JSBool) -> bool {
+ object: HandleObject,
+ property: &str,
+ rval: MutableHandleValue)
+ -> Result<bool, ()> {
+ fn has_property(cx: *mut JSContext, object: HandleObject, property: &CString,
+ found: &mut u8) -> bool {
unsafe {
JS_HasProperty(cx, object, property.as_ptr(), found) != 0
}
}
- fn get_property(cx: *mut JSContext, object: *mut JSObject, property: &CString,
- value: &mut JSVal) -> bool {
+ fn get_property(cx: *mut JSContext, object: HandleObject, property: &CString,
+ value: MutableHandleValue) -> bool {
unsafe {
JS_GetProperty(cx, object, property.as_ptr(), value) != 0
}
}
let property = CString::new(property).unwrap();
- if object.is_null() {
- return Ok(None);
+ if object.get().is_null() {
+ return Ok(false);
}
- let mut found: JSBool = 0;
+ let mut found: u8 = 0;
if !has_property(cx, object, &property, &mut found) {
return Err(());
}
if found == 0 {
- return Ok(None);
+ return Ok(false);
}
- let mut value = NullValue();
- if !get_property(cx, object, &property, &mut value) {
+ if !get_property(cx, object, &property, rval) {
return Err(());
}
- Ok(Some(value))
+ Ok(true)
}
/// Set the property with name `property` from `object`.
/// Returns `Err(())` on JSAPI failure, or null object,
/// and Ok(()) otherwise
pub fn set_dictionary_property(cx: *mut JSContext,
- object: *mut JSObject,
+ object: HandleObject,
property: &str,
- value: &mut JSVal) -> Result<(), ()> {
- if object.is_null() {
+ value: HandleValue) -> Result<(), ()> {
+ if object.get().is_null() {
return Err(());
}
@@ -569,79 +575,99 @@ pub fn set_dictionary_property(cx: *mut JSContext,
}
/// Returns whether `proxy` has a property `id` on its prototype.
-pub fn has_property_on_prototype(cx: *mut JSContext, proxy: *mut JSObject,
- id: jsid) -> bool {
+pub fn has_property_on_prototype(cx: *mut JSContext, proxy: HandleObject,
+ id: HandleId) -> bool {
// MOZ_ASSERT(js::IsProxy(proxy) && js::GetProxyHandler(proxy) == handler);
let mut found = false;
- return !get_property_on_prototype(cx, proxy, id, &mut found, ptr::null_mut()) || found;
+ return !get_property_on_prototype(cx, proxy, id, &mut found,
+ MutableHandleValue { ptr: ptr::null_mut() }) || found;
}
/// Create a DOM global object with the given class.
-pub fn create_dom_global(cx: *mut JSContext, class: *const JSClass)
+pub fn create_dom_global(cx: *mut JSContext, class: *const JSClass,
+ trace: JSTraceOp)
-> *mut JSObject {
unsafe {
- let obj = JS_NewGlobalObject(cx, class, ptr::null_mut());
- if obj.is_null() {
+ let mut options = CompartmentOptions::default();
+ options.version_ = JSVersion::JSVERSION_LATEST;
+ options.traceGlobal_ = trace;
+
+ let obj =
+ RootedObject::new(cx,
+ JS_NewGlobalObject(cx, class, ptr::null_mut(),
+ OnNewGlobalHookOption::DontFireOnNewGlobalHook, &options));
+ if obj.ptr.is_null() {
return ptr::null_mut();
}
- with_compartment(cx, obj, || {
- JS_InitStandardClasses(cx, obj);
- });
- initialize_global(obj);
- obj
+ let _ac = JSAutoCompartment::new(cx, obj.ptr);
+ JS_InitStandardClasses(cx, obj.handle());
+ initialize_global(obj.ptr);
+ JS_FireOnNewGlobalObject(cx, obj.handle());
+ obj.ptr
}
}
/// Drop the resources held by reserved slots of a global object
pub unsafe fn finalize_global(obj: *mut JSObject) {
+ let protolist = get_proto_or_iface_array(obj);
+ let list = (*protolist).as_mut_ptr();
+ for idx in 0..(PrototypeList::ID::Count as isize) {
+ let entry = list.offset(idx);
+ let value = *entry;
+ if <*mut JSObject>::needs_post_barrier(value) {
+ <*mut JSObject>::relocate(entry);
+ }
+ }
let _: Box<ProtoOrIfaceArray> =
- Box::from_raw(get_proto_or_iface_array(obj));
+ Box::from_raw(protolist);
}
/// Trace the resources held by reserved slots of a global object
pub unsafe fn trace_global(tracer: *mut JSTracer, obj: *mut JSObject) {
let array = get_proto_or_iface_array(obj);
- for &proto in (*array).iter() {
+ for proto in (&*array).iter() {
if !proto.is_null() {
- trace_object(tracer, "prototype", proto);
+ trace_object(tracer, "prototype", &*(proto as *const *mut JSObject as *const Heap<*mut JSObject>));
}
}
}
-/// 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)
+unsafe extern fn wrap(cx: *mut JSContext,
+ existing: HandleObject,
+ obj: HandleObject)
+ -> *mut JSObject {
+ // FIXME terrible idea. need security wrappers
+ // https://github.com/servo/servo/issues/2382
+ WrapperNew(cx, obj, GetCrossCompartmentWrapper())
}
-/// Callback to outerize windows before wrapping.
-pub unsafe extern fn pre_wrap(cx: *mut JSContext, _scope: *mut JSObject,
- obj: *mut JSObject, _flags: c_uint) -> *mut JSObject {
+unsafe extern fn pre_wrap(cx: *mut JSContext, _existing: HandleObject,
+ obj: HandleObject, _object_passed_to_wrap: HandleObject)
+ -> *mut JSObject {
+ let _ac = JSAutoCompartment::new(cx, obj.get());
JS_ObjectToOuterObject(cx, obj)
}
+/// Callback table for use with JS_SetWrapObjectCallbacks
+pub static WRAP_CALLBACKS: JSWrapObjectCallbacks = JSWrapObjectCallbacks {
+ wrap: Some(wrap),
+ preWrap: Some(pre_wrap),
+};
+
/// 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<window::Window> = native_from_reflector_jsmanaged(obj).unwrap().root();
- // FIXME(https://github.com/rust-lang/rust/issues/23338)
- let win = win.r();
- let context = win.browser_context();
- context.as_ref().unwrap().window_proxy()
- }
+pub unsafe extern fn outerize_global(_cx: *mut JSContext, obj: HandleObject) -> *mut JSObject {
+ debug!("outerizing");
+ let win: Root<window::Window> = native_from_handleobject(obj).unwrap();
+ // FIXME(https://github.com/rust-lang/rust/issues/23338)
+ let win = win.r();
+ let context = win.browser_context();
+ context.as_ref().unwrap().window_proxy()
}
/// Deletes the property `id` from `object`.
-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 {
- return false;
- }
-
- *bp = value.to_boolean();
- return true;
+pub unsafe fn delete_property_by_id(cx: *mut JSContext, object: HandleObject,
+ id: HandleId, bp: *mut ObjectOpResult) -> u8 {
+ JS_DeletePropertyById1(cx, object, id, bp)
}
/// Validate a qualified name. See https://dom.spec.whatwg.org/#validate for details.
@@ -659,6 +685,18 @@ pub fn validate_qualified_name(qualified_name: &str) -> ErrorResult {
}
}
+unsafe extern "C" fn instance_class_has_proto_at_depth(clasp: *const js::jsapi::Class,
+ proto_id: u32,
+ depth: u32) -> u8 {
+ let domclass: *const DOMJSClass = clasp as *const _;
+ let domclass = &*domclass;
+ (domclass.dom_class.interface_chain[depth as usize] as u32 == proto_id) as u8
+}
+
+pub const DOM_CALLBACKS: DOMCallbacks = DOMCallbacks {
+ instanceClassMatchesProto: Some(instance_class_has_proto_at_depth),
+};
+
/// Validate a namespace and qualified name and extract their parts.
/// See https://dom.spec.whatwg.org/#validate-and-extract for details.
pub fn validate_and_extract(namespace: Option<DOMString>, qualified_name: &str)