Auto merge of #20265 - Xanewok:fix-js-objects-in-unions, r=jdm

Fix JS object conversion in unions

<!-- Please describe your changes on the following line: -->
Requires safe `Heap::boxed` constructor from https://github.com/servo/rust-mozjs/pull/395 (more info on it is in the PR).

Since unions currently assume that their respective members root themselves and can be stored on heap, I modified the union member object conversion branch to convert to a `RootedTraceableBox<Heap<*mut JSObject>>` (which is the currently generated type for objects in said unions).

I did it only for Unions and not dictionaries, since some dictionaries had bare `*mut JSObject` members - is this a mistake and something that needs further fixing?

Does this need a test, e.g. passing a union with object to a function that returns said object, and comparing the results for equality?

r? @jdm

Generated code with this patch (for `StringOrObject`):
```rust
impl FromJSValConvertible for StringOrObject {
    type Config = ();
    unsafe fn from_jsval(cx: *mut JSContext,
                         value: HandleValue,
                         _option: ())
                         -> Result<ConversionResult<StringOrObject>, ()> {
        if value.get().is_object() {
            match StringOrObject::TryConvertToObject(cx, value) {
                Err(_) => return Err(()),
                Ok(Some(value)) => return Ok(ConversionResult::Success(StringOrObject::Object(value))),
                Ok(None) => (),
            }

        }
        // (...)
    }
}

impl StringOrObject {
    // (...)
    unsafe fn TryConvertToObject(cx: *mut JSContext, value: HandleValue) -> Result<Option<RootedTraceableBox<Heap<*mut JSObject>>>, ()> {
        Ok(Some(RootedTraceableBox::from_box(Heap::boxed(value.get().to_object()))))
    }
}
```

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [ ] These changes fix #17011 (github issue number if applicable).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/20265)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-03-14 12:04:23 -04:00 committed by GitHub
commit e597cd9e1a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 68 additions and 18 deletions

10
Cargo.lock generated
View file

@ -1620,7 +1620,7 @@ dependencies = [
"cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.23.2 (registry+https://github.com/rust-lang/crates.io-index)",
"euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"hashglobe 0.1.0", "hashglobe 0.1.0",
"mozjs 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "mozjs 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"selectors 0.19.0", "selectors 0.19.0",
"servo_arc 0.1.1", "servo_arc 0.1.1",
"smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "smallbitvec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1795,13 +1795,13 @@ dependencies = [
[[package]] [[package]]
name = "mozjs" name = "mozjs"
version = "0.1.11" version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"mozjs_sys 0.50.1 (registry+https://github.com/rust-lang/crates.io-index)", "mozjs_sys 0.50.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -2462,7 +2462,7 @@ dependencies = [
"mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "mime_guess 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"mozangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "mozangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"mozjs 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "mozjs 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
"msg 0.0.1", "msg 0.0.1",
"net_traits 0.0.1", "net_traits 0.0.1",
"num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
@ -3844,7 +3844,7 @@ dependencies = [
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9de3eca27871df31c33b807f834b94ef7d000956f57aa25c5aed9c5f0aae8f6f" "checksum mitochondria 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9de3eca27871df31c33b807f834b94ef7d000956f57aa25c5aed9c5f0aae8f6f"
"checksum mozangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4d916e4f2d39a00eeeb082ceb7c63c741e7c9d4f7915945f9225ae5e3b284092" "checksum mozangle 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4d916e4f2d39a00eeeb082ceb7c63c741e7c9d4f7915945f9225ae5e3b284092"
"checksum mozjs 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "199f707066bf05b559ef6e46741c20e4f7bca8ae3a9c9d953d728dbb840f4eaa" "checksum mozjs 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "23e86a4da33f9325da4ccc652506284e00ff20f06d63f721eaebeb804eaca62d"
"checksum mozjs_sys 0.50.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e61a792a125b1364c5ec50255ed8343ce02dc56098f8868dd209d472c8de006a" "checksum mozjs_sys 0.50.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e61a792a125b1364c5ec50255ed8343ce02dc56098f8868dd209d472c8de006a"
"checksum mp3-metadata 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ab5f1d2693586420208d1200ce5a51cd44726f055b635176188137aff42c7de" "checksum mp3-metadata 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ab5f1d2693586420208d1200ce5a51cd44726f055b635176188137aff42c7de"
"checksum mp4parse 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f821e3799bc0fd16d9b861fb02fa7ee1b5fba29f45ad591dade105c48ca9a1a0" "checksum mp4parse 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f821e3799bc0fd16d9b861fb02fa7ee1b5fba29f45ad591dade105c48ca9a1a0"

View file

@ -1075,20 +1075,24 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
if type.isObject(): if type.isObject():
assert not isEnforceRange and not isClamp assert not isEnforceRange and not isClamp
# TODO: Need to root somehow templateBody = "${val}.get().to_object()"
# https://github.com/servo/servo/issues/6382
default = "ptr::null_mut()" default = "ptr::null_mut()"
templateBody = wrapObjectTemplate("${val}.get().to_object()",
default,
isDefinitelyObject, type, failureCode)
if isMember in ("Dictionary", "Union"): # TODO: Do we need to do the same for dictionaries?
if isMember == "Union":
templateBody = "RootedTraceableBox::from_box(Heap::boxed(%s))" % templateBody
default = "RootedTraceableBox::new(Heap::default())"
declType = CGGeneric("RootedTraceableBox<Heap<*mut JSObject>>")
elif isMember == "Dictionary":
declType = CGGeneric("Heap<*mut JSObject>") declType = CGGeneric("Heap<*mut JSObject>")
else: else:
# TODO: Need to root somehow # TODO: Need to root somehow
# https://github.com/servo/servo/issues/6382 # https://github.com/servo/servo/issues/6382
declType = CGGeneric("*mut JSObject") declType = CGGeneric("*mut JSObject")
templateBody = wrapObjectTemplate(templateBody, default,
isDefinitelyObject, type, failureCode)
return handleOptional(templateBody, declType, return handleOptional(templateBody, declType,
handleDefaultNull(default)) handleDefaultNull(default))
@ -4291,11 +4295,13 @@ class CGUnionConversionStruct(CGThing):
else: else:
mozMapObject = None mozMapObject = None
hasObjectTypes = interfaceObject or arrayObject or dateObject or object or mozMapObject hasObjectTypes = object or interfaceObject or arrayObject or dateObject or mozMapObject
if hasObjectTypes: if hasObjectTypes:
# "object" is not distinguishable from other types # "object" is not distinguishable from other types
assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject) assert not object or not (interfaceObject or arrayObject or dateObject or callbackObject or mozMapObject)
templateBody = CGList([], "\n") templateBody = CGList([], "\n")
if object:
templateBody.append(object)
if interfaceObject: if interfaceObject:
templateBody.append(interfaceObject) templateBody.append(interfaceObject)
if arrayObject: if arrayObject:
@ -4363,11 +4369,6 @@ class CGUnionConversionStruct(CGThing):
returnType = "Result<Option<%s>, ()>" % actualType returnType = "Result<Option<%s>, ()>" % actualType
jsConversion = templateVars["jsConversion"] jsConversion = templateVars["jsConversion"]
# Any code to convert to Object is unused, since we're already converting
# from an Object value.
if t.name == 'Object':
return CGGeneric('')
return CGWrapper( return CGWrapper(
CGIndenter(jsConversion, 4), CGIndenter(jsConversion, 4),
pre="unsafe fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n" pre="unsafe fn TryConvertTo%s(cx: *mut JSContext, value: HandleValue) -> %s {\n"

View file

@ -765,7 +765,12 @@ unsafe impl<T: JSTraceable + 'static> JSTraceable for RootedTraceableBox<T> {
impl<T: JSTraceable + 'static> RootedTraceableBox<T> { impl<T: JSTraceable + 'static> RootedTraceableBox<T> {
/// DomRoot a JSTraceable thing for the life of this RootedTraceable /// DomRoot a JSTraceable thing for the life of this RootedTraceable
pub fn new(traceable: T) -> RootedTraceableBox<T> { pub fn new(traceable: T) -> RootedTraceableBox<T> {
let traceable = Box::into_raw(Box::new(traceable)); Self::from_box(Box::new(traceable))
}
/// Consumes a boxed JSTraceable and roots it for the life of this RootedTraceable.
pub fn from_box(boxed_traceable: Box<T>) -> RootedTraceableBox<T> {
let traceable = Box::into_raw(boxed_traceable);
unsafe { unsafe {
RootedTraceableSet::add(traceable); RootedTraceableSet::add(traceable);
} }

View file

@ -293,6 +293,14 @@ impl TestBindingMethods for TestBinding {
fn ReceiveInterfaceSequence(&self) -> Vec<DomRoot<Blob>> { fn ReceiveInterfaceSequence(&self) -> Vec<DomRoot<Blob>> {
vec![Blob::new(&self.global(), BlobImpl::new_from_bytes(vec![]), "".to_owned())] vec![Blob::new(&self.global(), BlobImpl::new_from_bytes(vec![]), "".to_owned())]
} }
#[allow(unsafe_code)]
unsafe fn ReceiveUnionIdentity(
&self,
_: *mut JSContext,
arg: UnionTypes::StringOrObject,
) -> UnionTypes::StringOrObject {
arg
}
fn ReceiveNullableBoolean(&self) -> Option<bool> { Some(false) } fn ReceiveNullableBoolean(&self) -> Option<bool> { Some(false) }
fn ReceiveNullableByte(&self) -> Option<i8> { Some(0) } fn ReceiveNullableByte(&self) -> Option<i8> { Some(0) }

View file

@ -228,6 +228,8 @@ interface TestBinding {
TestDictionary receiveTestDictionaryWithSuccessOnKeyword(); TestDictionary receiveTestDictionaryWithSuccessOnKeyword();
boolean dictMatchesPassedValues(TestDictionary arg); boolean dictMatchesPassedValues(TestDictionary arg);
(DOMString or object) receiveUnionIdentity((DOMString or object) arg);
void passBoolean(boolean arg); void passBoolean(boolean arg);
void passByte(byte arg); void passByte(byte arg);
void passOctet(octet arg); void passOctet(octet arg);

View file

@ -31972,6 +31972,12 @@
{} {}
] ]
], ],
"mozilla/codegen_unions.html": [
[
"/_mozilla/mozilla/codegen_unions.html",
{}
]
],
"mozilla/collections.html": [ "mozilla/collections.html": [
[ [
"/_mozilla/mozilla/collections.html", "/_mozilla/mozilla/collections.html",
@ -64751,6 +64757,10 @@
"5183977a0d29ba4d74d049c9391090e3c27264a8", "5183977a0d29ba4d74d049c9391090e3c27264a8",
"testharness" "testharness"
], ],
"mozilla/codegen_unions.html": [
"7f772fffb75acc92f9c949a482d387b3ed18d0ed",
"testharness"
],
"mozilla/collections.html": [ "mozilla/collections.html": [
"d0bebe808ebb45b6c853f4b88e1a6ebbf9b91345", "d0bebe808ebb45b6c853f4b88e1a6ebbf9b91345",
"testharness" "testharness"

View file

@ -0,0 +1,3 @@
[codegen_unions.html]
type: testharness
prefs: [dom.testbinding.enabled:true]

View file

@ -0,0 +1,21 @@
<!doctype html>
<html>
<meta charset="utf-8">
<title>WebIDL conversions are performed correctly and don't lose values</title>
<head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
</head>
<script>
test(function() {
var t = new TestBinding;
// (DOMString or object) receiveUnionIdentity((DOMString or object) arg)
var obj = { 'some': 'key', 'num': 42 };
assert_equals(t.receiveUnionIdentity(obj), obj);
var str = "myString";
assert_equals(t.receiveUnionIdentity(str), str);
}, "(DOMString or object) conversion is performed correctly");
</script>
</html>