Skip to content

Commit ae642f8

Browse files
authored
Add minimal bindings for Handle<StackGCVector<T>>. (#620)
* Add minimal bindings for Handle<StackGCVector<T>>. Signed-off-by: Josh Matthews <[email protected]> * Add unit test. Signed-off-by: Josh Matthews <[email protected]> * Add missing glue wrappers. Signed-off-by: Josh Matthews <[email protected]> * Avoid returning non-POD datatypes. Signed-off-by: Josh Matthews <[email protected]> * Fix build error. Signed-off-by: Josh Matthews <[email protected]> * Remove some raw handle usage. Signed-off-by: Josh Matthews <[email protected]> * Fix build error. Signed-off-by: Josh Matthews <[email protected]> * Detect gfind/find when generating wrappers. Signed-off-by: Josh Matthews <[email protected]> * Format. Signed-off-by: Josh Matthews <[email protected]> --------- Signed-off-by: Josh Matthews <[email protected]>
1 parent 6a966a7 commit ae642f8

File tree

9 files changed

+181
-7
lines changed

9 files changed

+181
-7
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.0-2"
5+
version = "0.140.0-3"
66
authors = ["Mozilla"]
77
links = "mozjs"
88
license.workspace = true

mozjs-sys/build.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,9 @@ impl BuildTarget {
758758
// is more than bindgen can cope with.
759759
"JS::Rooted",
760760
// We don't need them and bindgen doesn't like them.
761+
"JS::StackGCVector.*",
762+
"JS::RootedVector_Vec",
763+
"JS::RootedVector_Base",
761764
"JS::HandleVector",
762765
"JS::MutableHandleVector",
763766
"JS::Rooted.*Vector",
@@ -842,7 +845,6 @@ impl BuildTarget {
842845
match self {
843846
BuildTarget::JSApi => &[
844847
"JS::EnvironmentChain",
845-
"JS::StackGCVector.*",
846848
"JS::PersistentRooted.*",
847849
"JS::detail::CallArgsBase",
848850
"js::detail::UniqueSelector.*",
@@ -860,7 +862,6 @@ impl BuildTarget {
860862
],
861863
BuildTarget::JSGlue => &[
862864
"JS::Auto.*Impl",
863-
"JS::StackGCVector.*",
864865
"JS::PersistentRooted.*",
865866
"JS::detail::CallArgsBase.*",
866867
"js::detail::UniqueSelector.*",
@@ -882,6 +883,7 @@ impl BuildTarget {
882883
("root", "pub type FILE = ::libc::FILE;"),
883884
("root::JS", "pub type Heap<T> = crate::jsgc::Heap<T>;"),
884885
("root::JS", "pub type Rooted<T> = crate::jsgc::Rooted<T>;"),
886+
("root::JS", "pub type StackGCVector<T, AllocPolicy> = crate::jsgc::StackGCVector<T, AllocPolicy>;"),
885887
],
886888
BuildTarget::JSGlue => &[
887889
("root", "pub(crate) use crate::jsapi::*;"),

mozjs-sys/src/jsgc.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
* License, v. 2.0. If a copy of the MPL was not distributed with this
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44

5-
use crate::jsapi::JS;
5+
use crate::jsapi::{js, JS};
66
use crate::jsapi::{jsid, JSFunction, JSObject, JSScript, JSString, JSTracer};
77
use crate::jsid::VoidId;
88
use std::cell::UnsafeCell;
99
use std::ffi::{c_char, c_void};
10+
use std::marker::PhantomData;
1011
use std::mem;
1112
use std::ptr;
1213

@@ -462,3 +463,7 @@ impl CustomAutoRooterVFTable {
462463
#[cfg(not(windows))]
463464
pub const PADDING: [usize; 2] = [0, 0];
464465
}
466+
467+
#[repr(C)]
468+
#[derive(Copy, Clone)]
469+
pub struct StackGCVector<T, AllocPolicy = js::TempAllocPolicy>(PhantomData<(T, AllocPolicy)>, u8);

mozjs-sys/src/jsglue.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,4 +1205,24 @@ void DumpJSStack(JSContext* cx, bool showArgs, bool showLocals,
12051205
printf("%s\n", buf.get());
12061206
}
12071207

1208+
uint32_t StackGCVectorValueLength(
1209+
JS::Handle<JS::StackGCVector<JS::Value>> vec) {
1210+
return vec.length();
1211+
}
1212+
1213+
uint32_t StackGCVectorStringLength(
1214+
JS::Handle<JS::StackGCVector<JSString*>> vec) {
1215+
return vec.length();
1216+
}
1217+
1218+
const JS::Value* StackGCVectorValueAtIndex(
1219+
JS::Handle<JS::StackGCVector<JS::Value>> vec, uint32_t index) {
1220+
return vec.begin() + index;
1221+
}
1222+
1223+
JSString* const* StackGCVectorStringAtIndex(
1224+
JS::Handle<JS::StackGCVector<JSString*>> vec, uint32_t index) {
1225+
return vec.begin() + index;
1226+
}
1227+
12081228
} // extern "C"

mozjs/src/gc/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pub use crate::gc::collections::*;
22
pub use crate::gc::custom::*;
33
pub use crate::gc::root::*;
44
pub use crate::gc::trace::*;
5-
pub use mozjs_sys::jsgc::{GCMethods, Initialize, RootKind, Rootable};
5+
pub use mozjs_sys::jsgc::{GCMethods, Initialize, RootKind, Rootable, StackGCVector};
66
pub use mozjs_sys::trace::Traceable;
77

88
mod collections;

mozjs/src/generate_wrappers.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/bin/sh
22
# Detect gsed or sed
33
gsed=$(type gsed >/dev/null 2>&1 && echo gsed || echo sed)
4+
# Detect gfind or find
5+
gfind=$(type gfind >/dev/null 2>&1 && echo gfind || echo find)
46
# This is one big heuristic but seems to work well enough
57
grep_heur() {
68
grep -v "link_name" "$1" | \
@@ -24,14 +26,16 @@ grep_heur() {
2426
$gsed 's/mozilla:://g' |
2527
$gsed 's/Handle<\*mut JSObject>/HandleObject/g' |
2628
grep -F -v '> HandleObject' | # We are only wrapping handles in args not in results
29+
grep -F -v '> HandleValue' |
30+
grep -F -v '> HandleString' |
2731
grep -v 'MutableHandleObjectVector' # GetDebuggeeGlobals has it
2832
}
2933

3034
# usage find_latest_version_of_file_and_parse $input_file $out_wrapper_module_name
3135
find_latest_version_of_file_and_parse() {
3236
# clone file and reformat (this is needed for grep_heur to work properly)
3337
# this $(find) only gets last modified file
34-
cp $(find target -name "$1" -printf "%T@ %p\n" | sort -n | tail -n 1 | tr ' ' '\n' | tail -n 1) "target/wrap_$1"
38+
cp $($gfind target -name "$1" -printf "%T@ %p\n" | sort -n | tail -n 1 | tr ' ' '\n' | tail -n 1) "target/wrap_$1"
3539
rustfmt "target/wrap_$1" --config max_width=1000
3640

3741
# parse reformated file

mozjs/src/glue_wrappers.in.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,7 @@ wrap!(glue: pub fn JS_GetRegExpFlags(cx: *mut JSContext, obj: HandleObject, flag
2424
wrap!(glue: pub fn EncodeStringToUTF8(cx: *mut JSContext, str_: HandleString, cb: EncodedStringCallback));
2525
wrap!(glue: pub fn SetDataPropertyDescriptor(desc: MutableHandle<PropertyDescriptor>, value: HandleValue, attrs: u32));
2626
wrap!(glue: pub fn SetAccessorPropertyDescriptor(desc: MutableHandle<PropertyDescriptor>, getter: HandleObject, setter: HandleObject, attrs: u32));
27+
wrap!(glue: pub fn StackGCVectorValueLength(vec: Handle<StackGCVector<Value, TempAllocPolicy>>) -> u32);
28+
wrap!(glue: pub fn StackGCVectorStringLength(vec: Handle<StackGCVector<*mut JSString, TempAllocPolicy>>) -> u32);
29+
wrap!(glue: pub fn StackGCVectorValueAtIndex(vec: Handle<StackGCVector<Value, TempAllocPolicy>>, index: u32) -> *const Value);
30+
wrap!(glue: pub fn StackGCVectorStringAtIndex(vec: Handle<StackGCVector<*mut JSString, TempAllocPolicy>>, index: u32) -> *const *mut JSString);

mozjs/src/rust.rs

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ use std::str;
1717
use std::sync::atomic::{AtomicU32, Ordering};
1818
use std::sync::{Arc, Mutex, RwLock};
1919

20+
use self::wrappers::{
21+
StackGCVectorStringAtIndex, StackGCVectorStringLength, StackGCVectorValueAtIndex,
22+
StackGCVectorValueLength,
23+
};
2024
use crate::consts::{JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_RESERVED_SLOTS_MASK};
2125
use crate::consts::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
2226
use crate::conversions::jsstr_to_string;
@@ -33,6 +37,7 @@ use crate::glue::{
3337
};
3438
use crate::jsapi;
3539
use crate::jsapi::glue::{DeleteRealmOptions, JS_Init, JS_NewRealmOptions};
40+
use crate::jsapi::js;
3641
use crate::jsapi::js::frontend::InitialStencilAndDelazifications;
3742
use crate::jsapi::mozilla::Utf8Unit;
3843
use crate::jsapi::shadow::BaseShape;
@@ -61,7 +66,7 @@ use crate::jsapi::{PersistentRootedObjectVector, ReadOnlyCompileOptions, Rooting
6166
use crate::jsapi::{SetWarningReporter, SourceText, ToBooleanSlow};
6267
use crate::jsapi::{ToInt32Slow, ToInt64Slow, ToNumberSlow, ToStringSlow, ToUint16Slow};
6368
use crate::jsapi::{ToUint32Slow, ToUint64Slow, ToWindowProxyIfWindowSlow};
64-
use crate::jsval::ObjectValue;
69+
use crate::jsval::{JSVal, ObjectValue};
6570
use crate::panic::maybe_resume_unwind;
6671
use log::{debug, warn};
6772
use mozjs_sys::jsapi::JS::SavedFrameResult;
@@ -1154,6 +1159,36 @@ impl Drop for EnvironmentChain {
11541159
}
11551160
}
11561161

1162+
impl<'a> Handle<'a, StackGCVector<JSVal, js::TempAllocPolicy>> {
1163+
pub fn at(&'a self, index: u32) -> Option<Handle<'a, JSVal>> {
1164+
if index >= self.len() {
1165+
return None;
1166+
}
1167+
let handle =
1168+
unsafe { Handle::from_marked_location(StackGCVectorValueAtIndex(*self, index)) };
1169+
Some(handle)
1170+
}
1171+
1172+
pub fn len(&self) -> u32 {
1173+
unsafe { StackGCVectorValueLength(*self) }
1174+
}
1175+
}
1176+
1177+
impl<'a> Handle<'a, StackGCVector<*mut JSString, js::TempAllocPolicy>> {
1178+
pub fn at(&'a self, index: u32) -> Option<Handle<'a, *mut JSString>> {
1179+
if index >= self.len() {
1180+
return None;
1181+
}
1182+
let handle =
1183+
unsafe { Handle::from_marked_location(StackGCVectorStringAtIndex(*self, index)) };
1184+
Some(handle)
1185+
}
1186+
1187+
pub fn len(&self) -> u32 {
1188+
unsafe { StackGCVectorStringLength(*self) }
1189+
}
1190+
}
1191+
11571192
/// Wrappers for JSAPI methods that accept lifetimed Handle and MutableHandle arguments
11581193
pub mod wrappers {
11591194
macro_rules! wrap {
@@ -1239,6 +1274,7 @@ pub mod wrappers {
12391274
use crate::glue;
12401275
use crate::glue::EncodedStringCallback;
12411276
use crate::jsapi;
1277+
use crate::jsapi::js::TempAllocPolicy;
12421278
use crate::jsapi::jsid;
12431279
use crate::jsapi::mozilla::Utf8Unit;
12441280
use crate::jsapi::BigInt;

mozjs/tests/stack_gc_vector.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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+
use std::ptr::{self, NonNull};
6+
use std::sync::{LazyLock, Mutex};
7+
8+
use mozjs::conversions::jsstr_to_string;
9+
use mozjs::gc::StackGCVector;
10+
use mozjs::jsapi::{
11+
CompilationType, Handle, HandleString, HandleValue, JSContext, JSSecurityCallbacks, JSString,
12+
JS_NewGlobalObject, JS_SetSecurityCallbacks, OnNewGlobalHookOption, RuntimeCode,
13+
};
14+
use mozjs::jsval::{JSVal, UndefinedValue};
15+
use mozjs::rooted;
16+
use mozjs::rust::{Handle as SafeHandle, JSEngine, RealmOptions, Runtime, SIMPLE_GLOBAL_CLASS};
17+
18+
static SECURITY_CALLBACKS: JSSecurityCallbacks = JSSecurityCallbacks {
19+
contentSecurityPolicyAllows: Some(content_security_policy_allows),
20+
codeForEvalGets: None,
21+
subsumes: None,
22+
};
23+
24+
unsafe extern "C" fn content_security_policy_allows(
25+
cx: *mut JSContext,
26+
_runtime_code: RuntimeCode,
27+
_code_string: HandleString,
28+
_compilation_type: CompilationType,
29+
parameter_strings: Handle<StackGCVector<*mut JSString>>,
30+
_body_string: HandleString,
31+
parameter_args: Handle<StackGCVector<JSVal>>,
32+
_body_arg: HandleValue,
33+
can_compile_strings: *mut bool,
34+
) -> bool {
35+
let parameter_strings = SafeHandle::from_raw(parameter_strings);
36+
assert_eq!(parameter_strings.len(), 2);
37+
38+
let string0 = parameter_strings.at(0).expect("should have a value");
39+
let string0 = NonNull::new(*string0).expect("should be non-null");
40+
assert_eq!(jsstr_to_string(cx, string0), "a".to_string());
41+
42+
let string1 = parameter_strings.at(1).expect("should have a value");
43+
let string1 = NonNull::new(*string1).expect("should be non-null");
44+
assert_eq!(jsstr_to_string(cx, string1), "b".to_string());
45+
46+
let parameter_args = SafeHandle::from_raw(parameter_args);
47+
assert_eq!(parameter_args.len(), 2);
48+
49+
let arg0 = parameter_args.at(0).expect("should have a value");
50+
let string0 = arg0.to_string();
51+
let string0 = NonNull::new(string0).expect("should be non-null");
52+
assert_eq!(jsstr_to_string(cx, string0), "a".to_string());
53+
54+
let arg1 = parameter_args.at(1).expect("should have a value");
55+
let string1 = arg1.to_string();
56+
let string1 = NonNull::new(string1).expect("should be non-null");
57+
assert_eq!(jsstr_to_string(cx, string1), "b".to_string());
58+
59+
*RAN_CSP_CALLBACK.lock().unwrap() = true;
60+
*can_compile_strings = true;
61+
true
62+
}
63+
64+
static RAN_CSP_CALLBACK: LazyLock<Mutex<bool>> = LazyLock::new(|| Mutex::new(false));
65+
66+
#[test]
67+
fn csp_allow_arguments() {
68+
let engine = JSEngine::init().unwrap();
69+
let runtime = Runtime::new(engine.handle());
70+
let context = runtime.cx();
71+
#[cfg(feature = "debugmozjs")]
72+
unsafe {
73+
mozjs::jsapi::SetGCZeal(context, 2, 1);
74+
}
75+
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
76+
let c_option = RealmOptions::default();
77+
78+
unsafe {
79+
JS_SetSecurityCallbacks(context, &SECURITY_CALLBACKS);
80+
81+
rooted!(in(context) let global = JS_NewGlobalObject(
82+
context,
83+
&SIMPLE_GLOBAL_CLASS,
84+
ptr::null_mut(),
85+
h_option,
86+
&*c_option,
87+
));
88+
89+
rooted!(in(context) let mut rval = UndefinedValue());
90+
let options = runtime.new_compile_options("test", 1);
91+
assert!(runtime
92+
.evaluate_script(
93+
global.handle(),
94+
"Function(\"a\", \"b\", \"return a + b\")",
95+
rval.handle_mut(),
96+
options
97+
)
98+
.is_ok());
99+
assert!(rval.get().is_object());
100+
101+
assert!(*RAN_CSP_CALLBACK.lock().unwrap());
102+
}
103+
}

0 commit comments

Comments
 (0)