Skip to content

Commit 48bf97d

Browse files
authored
Support using rooted macro with vectors. (#697)
We created our `RootedVec` type back before we supported storing arbitrary traceable types in SpiderMonkey's `Rooted` class. Now that we can do that, we can replicate SpiderMonkey's `RootedVec`, which is just a Rooted wrapper around a vector. Testing: New unit test added. Servo PR: servo/servo#41921 --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
1 parent 78f08ed commit 48bf97d

File tree

6 files changed

+106
-4
lines changed

6 files changed

+106
-4
lines changed

mozjs-sys/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "mozjs_sys"
33
description = "System crate for the Mozilla SpiderMonkey JavaScript engine."
44
repository.workspace = true
5-
version = "0.140.5-8"
5+
version = "0.140.5-9"
66
authors = ["Mozilla", "The Servo Project Developers"]
77
links = "mozjs"
88
license.workspace = true

mozjs-sys/src/jsgc.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ pub trait Rootable: crate::trace::Traceable + Sized {
110110
}
111111

112112
impl<T: Rootable> Rootable for Option<T> {}
113+
impl<T: crate::trace::Traceable> Rootable for Vec<T> {}
113114

114115
// The C++ representation of Rooted<T> inherits from StackRootedBase, which
115116
// contains the actual pointers that get manipulated. The Rust representation

mozjs/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "mozjs"
33
description = "Rust bindings to the Mozilla SpiderMonkey JavaScript engine."
44
repository.workspace = true
5-
version = "0.14.6"
5+
version = "0.14.7"
66
authors = ["The Servo Project Developers"]
77
license.workspace = true
88
edition.workspace = true
@@ -26,7 +26,7 @@ crown = ["mozjs_sys/crown"]
2626
encoding_rs = "0.8.35"
2727
libc.workspace = true
2828
log = "0.4"
29-
mozjs_sys = { version = "=0.140.5-8", path = "../mozjs-sys" }
29+
mozjs_sys = { version = "=0.140.5-9", path = "../mozjs-sys" }
3030
num-traits = "0.2"
3131

3232
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]

mozjs/src/gc/collections.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ impl From<&RootedVec<'_, JSVal>> for JS::HandleValueArray {
4949
}
5050
}
5151

52+
impl From<&super::RootedGuard<'_, Vec<JSVal>>> for JS::HandleValueArray {
53+
fn from(vec: &super::RootedGuard<'_, Vec<JSVal>>) -> JS::HandleValueArray {
54+
JS::HandleValueArray {
55+
length_: vec.len(),
56+
elements_: vec.deref().as_ptr(),
57+
}
58+
}
59+
}
60+
5261
impl<'a, T: Traceable + 'static> RootedVec<'a, T> {
5362
pub fn new(root: &'a mut RootableVec<T>) -> RootedVec<'a, T> {
5463
unsafe {

mozjs/src/gc/root.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::marker::PhantomData;
22
use std::mem::MaybeUninit;
3-
use std::ops::Deref;
3+
use std::ops::{Deref, IndexMut};
44
use std::ptr;
55
use std::ptr::NonNull;
66

@@ -135,6 +135,40 @@ where
135135
}
136136
}
137137

138+
impl<'a, T> RootedGuard<'a, Vec<T>>
139+
where
140+
Vec<T>: RootKind,
141+
{
142+
pub fn push(&mut self, value: T) {
143+
// Safety: No GC occurs during this call
144+
unsafe { self.as_mut().push(value) }
145+
}
146+
147+
pub fn extend(&mut self, iterator: impl Iterator<Item = T>) {
148+
// Safety: No GC occurs during this call
149+
unsafe { self.as_mut().extend(iterator) }
150+
}
151+
152+
pub fn set_index(&mut self, index: usize, value: T) {
153+
// Safety: No GC occurs during this call
154+
unsafe {
155+
*self.as_mut().index_mut(index) = value;
156+
}
157+
}
158+
159+
pub fn handle_at(&'_ self, index: usize) -> Handle<'_, T> {
160+
assert!(index < self.len());
161+
// Safety: Values within this rooted vector are traced.
162+
unsafe { Handle::from_marked_location(self.deref().as_ptr().add(index)) }
163+
}
164+
165+
pub fn handle_mut_at(&'_ mut self, index: usize) -> MutableHandle<'_, T> {
166+
assert!(index < self.len());
167+
// Safety: Values within this rooted vector are traced.
168+
unsafe { MutableHandle::from_marked_location(self.as_mut().as_mut_ptr().add(index)) }
169+
}
170+
}
171+
138172
impl<'a, T: 'a + RootKind> Deref for RootedGuard<'a, T> {
139173
type Target = T;
140174

mozjs/tests/rooted_vec.rs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/* This Source Code Form is subject to the terms of the Mozilla Public
2+
* License, v. 2.0. If a copy of the MPL was not distributed with this
3+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4+
5+
#![cfg(feature = "debugmozjs")]
6+
7+
use std::ptr;
8+
9+
use mozjs::jsapi::HandleValueArray;
10+
use mozjs::jsapi::OnNewGlobalHookOption;
11+
use mozjs::jsapi::SetGCZeal;
12+
use mozjs::jsval::{JSVal, ObjectValue};
13+
use mozjs::realm::AutoRealm;
14+
use mozjs::rooted;
15+
use mozjs::rust::wrappers2::{
16+
GetArrayLength, JS_GetElement, JS_NewGlobalObject, JS_NewPlainObject, NewArrayObject,
17+
};
18+
use mozjs::rust::{JSEngine, RealmOptions, Runtime, SIMPLE_GLOBAL_CLASS};
19+
20+
#[test]
21+
fn rooted_vec() {
22+
let engine = JSEngine::init().unwrap();
23+
let mut runtime = Runtime::new(engine.handle());
24+
let context = runtime.cx();
25+
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
26+
let c_option = RealmOptions::default();
27+
28+
unsafe {
29+
SetGCZeal(context.raw_cx(), 2, 1);
30+
rooted!(&in(context) let global = JS_NewGlobalObject(
31+
context,
32+
&SIMPLE_GLOBAL_CLASS,
33+
ptr::null_mut(),
34+
h_option,
35+
&*c_option,
36+
));
37+
let mut realm = AutoRealm::new_from_handle(context, global.handle());
38+
let mut context = &mut realm;
39+
rooted!(&in(context) let mut values = vec![]);
40+
for _ in 0..32 {
41+
values.push(ObjectValue(JS_NewPlainObject(&mut context)));
42+
}
43+
rooted!(&in(context) let array = NewArrayObject(&mut context, &HandleValueArray::from(&values)));
44+
let mut length = 0;
45+
assert!(GetArrayLength(&mut context, array.handle(), &mut length));
46+
assert_eq!(values.len(), length as usize);
47+
for index in 0..length {
48+
rooted!(&in(context) let mut element: JSVal);
49+
assert!(JS_GetElement(
50+
&mut context,
51+
array.handle(),
52+
index,
53+
element.handle_mut()
54+
));
55+
assert_eq!(values[index as usize], element.get());
56+
}
57+
}
58+
}

0 commit comments

Comments
 (0)