Bug 1421056 - Changes to the js Rust crate needed for Starling. r=till

Changes include: whitelisting more things in `bindgen`, exposing the builtin
micro-task queue, and more conversion implementations.
This commit is contained in:
Nick Fitzgerald 2017-11-27 15:58:00 -05:00
Родитель a02f536d6d
Коммит f73f7eecaf
12 изменённых файлов: 266 добавлений и 12 удалений

Просмотреть файл

@ -163,6 +163,7 @@ const WHITELIST_TYPES: &'static [&'static str] = &[
"js::ESClass",
"JS::ForOfIterator",
"JS::Handle",
"JS::HandleFunction",
"JS::HandleId",
"JS::HandleObject",
"JS::HandleString",
@ -226,6 +227,7 @@ const WHITELIST_TYPES: &'static [&'static str] = &[
"js::shadow::Object",
"js::shadow::ObjectGroup",
"JS::SourceBufferHolder",
"js::StackFormat",
"JSStructuredCloneCallbacks",
"JS::Symbol",
"JS::SymbolCode",
@ -254,6 +256,7 @@ const WHITELIST_VARS: &'static [&'static str] = &[
/// Functions we want to generate bindings to.
const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
"INTERNED_STRING_TO_JSID",
"ExceptionStackOrNull",
"JS_AddExtraGCRootsTracer",
"JS_AddInterruptCallback",
"JS::AddPromiseReactions",
@ -261,7 +264,9 @@ const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
"JS_AlreadyHasOwnPropertyById",
"JS_AtomizeAndPinString",
"js::AssertSameCompartment",
"JS::BuildStackString",
"JS::Call",
"JS_CallFunctionName",
"JS_CallFunctionValue",
"JS::CallOriginalPromiseThen",
"JS::CallOriginalPromiseResolve",
@ -288,6 +293,7 @@ const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
"JS_GetObjectPrototype",
"JS_GetObjectRuntime",
"JS_GetOwnPropertyDescriptorById",
"JS::GetPromiseResult",
"JS::GetPromiseState",
"JS_GetPropertyDescriptorById",
"js::GetPropertyKeys",
@ -322,6 +328,7 @@ const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
"JS_EnumerateStandardClasses",
"JS_ErrorFromException",
"JS_FireOnNewGlobalObject",
"JS_free",
"JS_GC",
"JS_GetArrayBufferData",
"JS_GetArrayBufferViewType",
@ -386,11 +393,13 @@ const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
"JS_ReadBytes",
"JS_ReadStructuredClone",
"JS_ReadUint32Pair",
"JS_RemoveExtraGCRootsTracer",
"js::RemoveRawValueRoot",
"JS_ReportErrorASCII",
"JS_ReportErrorNumberUTF8",
"JS_RequestInterruptCallback",
"JS_ResolveStandardClass",
"js::RunJobs",
"JS_SameValue",
"js::SetDOMCallbacks",
"js::SetDOMProxyInformation",
@ -408,6 +417,7 @@ const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
"JS_SetParallelParsingEnabled",
"JS_SetPendingException",
"js::SetPreserveWrapperCallback",
"JS::SetPromiseRejectionTrackerCallback",
"JS_SetPrototype",
"js::SetWindowProxy",
"js::SetWindowProxyClass",
@ -416,6 +426,7 @@ const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
"JS_SetWrapObjectCallbacks",
"JS_ShutDown",
"JS_SplicePrototype",
"js::StopDrainingJobQueue",
"JS_StrictPropertyStub",
"JS_StringEqualsAscii",
"JS_StringHasLatin1Chars",
@ -449,6 +460,8 @@ const WHITELIST_FUNCTIONS: &'static [&'static str] = &[
"js::UnwrapUint32Array",
"js::UnwrapUint8Array",
"js::UnwrapUint8ClampedArray",
"js::UseInternalJobQueues",
"JS_ValueToFunction",
];
/// Types that should be treated as an opaque blob of bytes whenever they show

Просмотреть файл

@ -102,6 +102,17 @@ pub enum ConversionResult<T> {
}
impl<T> ConversionResult<T> {
/// Map a function over the `Success` value.
pub fn map<F, U>(self, mut f: F) -> ConversionResult<U>
where
F: FnMut(T) -> U
{
match self {
ConversionResult::Success(t) => ConversionResult::Success(f(t)),
ConversionResult::Failure(e) => ConversionResult::Failure(e),
}
}
/// Returns Some(value) if it is `ConversionResult::Success`.
pub fn get_success_value(&self) -> Option<&T> {
match *self {
@ -137,6 +148,53 @@ pub enum ConversionBehavior {
Clamp,
}
/// Use `T` with `ConversionBehavior::Default` but without requiring any
/// `Config` associated type.
pub struct Default<T>(pub T);
impl<T> FromJSValConvertible for Default<T>
where
T: FromJSValConvertible<Config = ConversionBehavior>
{
type Config = ();
unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _: ())
-> Result<ConversionResult<Self>, ()> {
T::from_jsval(cx, val, ConversionBehavior::Default).map(|conv| conv.map(Default))
}
}
/// Use `T` with `ConversionBehavior::EnforceRange` but without requiring any
/// `Config` associated type.
pub struct EnforceRange<T>(pub T);
impl<T> FromJSValConvertible for EnforceRange<T>
where
T: FromJSValConvertible<Config = ConversionBehavior>
{
type Config = ();
unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _: ())
-> Result<ConversionResult<Self>, ()> {
T::from_jsval(cx, val, ConversionBehavior::EnforceRange)
.map(|conv| conv.map(EnforceRange))
}
}
/// Use `T` with `ConversionBehavior::Clamp` but without requiring any `Config`
/// associated type.
pub struct Clamp<T>(pub T);
impl<T> FromJSValConvertible for Clamp<T>
where
T: FromJSValConvertible<Config = ConversionBehavior>
{
type Config = ();
unsafe fn from_jsval(cx: *mut JSContext, val: JS::HandleValue, _: ())
-> Result<ConversionResult<Self>, ()> {
T::from_jsval(cx, val, ConversionBehavior::Clamp)
.map(|conv| conv.map(Clamp))
}
}
/// Try to cast the number to a smaller type, but
/// if it doesn't fit, it will return an error.
unsafe fn enforce_range<D>(cx: *mut JSContext, d: f64) -> Result<ConversionResult<D>, ()>
@ -677,3 +735,55 @@ impl ToJSValConvertible for Heap<*mut JSObject> {
maybe_wrap_object_or_null_value(cx, rval);
}
}
// JSFunction
impl ToJSValConvertible for *mut JSFunction {
#[inline]
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: JS::MutableHandleValue) {
rval.set(ObjectOrNullValue(*self as *mut JSObject));
maybe_wrap_object_or_null_value(cx, rval);
}
}
#[cfg(feature = "nonzero")]
impl ToJSValConvertible for NonZero<*mut JSFunction> {
#[inline]
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: JS::MutableHandleValue) {
use rust::maybe_wrap_object_value;
rval.set(ObjectValue(self.get() as *mut JSObject));
maybe_wrap_object_value(cx, rval);
}
}
impl ToJSValConvertible for Heap<*mut JSFunction> {
#[inline]
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: JS::MutableHandleValue) {
rval.set(ObjectOrNullValue(self.get() as *mut JSObject));
maybe_wrap_object_or_null_value(cx, rval);
}
}
impl ToJSValConvertible for JS::Handle<*mut JSFunction> {
#[inline]
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: JS::MutableHandleValue) {
rval.set(ObjectOrNullValue(self.get() as *mut JSObject));
maybe_wrap_object_or_null_value(cx, rval);
}
}
impl FromJSValConvertible for *mut JSFunction {
type Config = ();
unsafe fn from_jsval(cx: *mut JSContext,
val: JS::HandleValue,
_: ())
-> Result<ConversionResult<Self>, ()> {
let func = JS_ValueToFunction(cx, val);
if func.is_null() {
Ok(ConversionResult::Failure("value is not a function".into()))
} else {
Ok(ConversionResult::Success(func))
}
}
}

Просмотреть файл

@ -84,7 +84,11 @@ impl Runtime {
}
/// Creates a new `JSContext`.
pub fn new() -> Result<Runtime, ()> {
///
/// * `use_internal_job_queue`: If `true`, then SpiderMonkey's internal
/// micro-task job queue is used. If `false`, then it is up to you to
/// implement micro-tasks yourself.
pub fn new(use_internal_job_queue: bool) -> Result<Runtime, ()> {
if SHUT_DOWN.load(Ordering::SeqCst) {
return Err(());
}
@ -177,6 +181,10 @@ impl Runtime {
context.set(js_context);
});
if use_internal_job_queue {
assert!(js::UseInternalJobQueues(js_context, false));
}
JS::InitSelfHostedCode(js_context);
JS::SetWarningReporter(js_context, Some(report_warning));
@ -1098,3 +1106,126 @@ pub unsafe fn maybe_wrap_value(cx: *mut JSContext, rval: JS::MutableHandleValue)
maybe_wrap_object_value(cx, rval);
}
}
/// Equivalents of the JS_FN* macros.
impl JSFunctionSpec {
pub fn js_fs(name: *const ::std::os::raw::c_char,
func: JSNative,
nargs: u16,
flags: u16) -> JSFunctionSpec {
JSFunctionSpec {
name: name,
call: JSNativeWrapper {
op: func,
info: ptr::null(),
},
nargs: nargs,
flags: flags,
selfHostedName: 0 as *const _,
}
}
pub fn js_fn(name: *const ::std::os::raw::c_char,
func: JSNative,
nargs: u16,
flags: u16) -> JSFunctionSpec {
JSFunctionSpec {
name: name,
call: JSNativeWrapper {
op: func,
info: ptr::null(),
},
nargs: nargs,
flags: flags,
selfHostedName: 0 as *const _,
}
}
pub const NULL: JSFunctionSpec = JSFunctionSpec {
name: 0 as *const _,
call: JSNativeWrapper {
op: None,
info: 0 as *const _,
},
nargs: 0,
flags: 0,
selfHostedName: 0 as *const _,
};
}
/// Equivalents of the JS_PS* macros.
impl JSPropertySpec {
pub fn getter(name: *const ::std::os::raw::c_char, flags: u8, func: JSNative)
-> JSPropertySpec {
debug_assert_eq!(flags & !(JSPROP_ENUMERATE | JSPROP_PERMANENT), 0);
JSPropertySpec {
name: name,
flags: flags,
__bindgen_anon_1: JSPropertySpec__bindgen_ty_1 {
accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 {
getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 {
native: JSNativeWrapper {
op: func,
info: ptr::null(),
},
},
setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 {
native: JSNativeWrapper {
op: None,
info: ptr::null(),
},
}
}
}
}
}
pub fn getter_setter(name: *const ::std::os::raw::c_char,
flags: u8,
g_f: JSNative,
s_f: JSNative)
-> JSPropertySpec {
debug_assert_eq!(flags & !(JSPROP_ENUMERATE | JSPROP_PERMANENT), 0);
JSPropertySpec {
name: name,
flags: flags,
__bindgen_anon_1: JSPropertySpec__bindgen_ty_1 {
accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 {
getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 {
native: JSNativeWrapper {
op: g_f,
info: ptr::null(),
},
},
setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 {
native: JSNativeWrapper {
op: s_f,
info: ptr::null(),
},
}
}
}
}
}
pub const NULL: JSPropertySpec = JSPropertySpec {
name: 0 as *const _,
flags: 0,
__bindgen_anon_1: JSPropertySpec__bindgen_ty_1{
accessors: JSPropertySpec__bindgen_ty_1__bindgen_ty_1 {
getter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_1 {
native: JSNativeWrapper {
op: None,
info: 0 as *const _,
},
},
setter: JSPropertySpec__bindgen_ty_1__bindgen_ty_1__bindgen_ty_2 {
native: JSNativeWrapper {
op: None,
info: 0 as *const _,
},
}
}
}
};
}

Просмотреть файл

@ -25,7 +25,7 @@ use std::str;
#[test]
fn callback() {
let runtime = Runtime::new().unwrap();
let runtime = Runtime::new(false).unwrap();
let context = runtime.cx();
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
let c_option = CompartmentOptions::default();

Просмотреть файл

@ -21,7 +21,7 @@ use std::ptr;
#[test]
fn enumerate() {
let rt = Runtime::new().unwrap();
let rt = Runtime::new(false).unwrap();
let cx = rt.cx();
unsafe {

Просмотреть файл

@ -15,7 +15,7 @@ use std::ptr;
#[test]
fn evaluate() {
let rt = Runtime::new().unwrap();
let rt = Runtime::new(false).unwrap();
let cx = rt.cx();
unsafe {

Просмотреть файл

@ -15,7 +15,7 @@ use std::str;
#[test]
#[should_panic]
fn panic() {
let runtime = Runtime::new().unwrap();
let runtime = Runtime::new(false).unwrap();
let context = runtime.cx();
let h_option = JS::OnNewGlobalHookOption::FireOnNewGlobalHook;
let c_option = JS::CompartmentOptions::default();

Просмотреть файл

@ -17,7 +17,7 @@ use std::ptr;
#[test]
fn rooting() {
unsafe {
let runtime = Runtime::new().unwrap();
let runtime = Runtime::new(false).unwrap();
JS_SetGCZeal(runtime.cx(), 2, 1);
let cx = runtime.cx();

Просмотреть файл

@ -13,7 +13,7 @@ use std::ptr;
#[test]
fn runtime() {
unsafe {
let runtime = Runtime::new().unwrap();
let runtime = Runtime::new(false).unwrap();
let cx = runtime.cx();
let h_option = JS::OnNewGlobalHookOption::FireOnNewGlobalHook;
@ -28,7 +28,7 @@ fn runtime() {
rooted!(in(cx) let _object = JS_NewObject(cx, &CLASS as *const _));
}
assert!(Runtime::new().is_err());
assert!(Runtime::new(false).is_err());
}
unsafe extern fn finalize(_fop: *mut JSFreeOp, _object: *mut JSObject) {

Просмотреть файл

@ -15,7 +15,7 @@ use std::ptr;
#[test]
fn stack_limit() {
let rt = Runtime::new().unwrap();
let rt = Runtime::new(false).unwrap();
let cx = rt.cx();
unsafe {

Просмотреть файл

@ -14,7 +14,7 @@ use std::ptr;
#[test]
fn typedarray() {
let rt = Runtime_::new().unwrap();
let rt = Runtime_::new(false).unwrap();
let cx = rt.cx();
unsafe {
@ -72,7 +72,7 @@ fn typedarray() {
#[test]
#[should_panic]
fn typedarray_update_panic() {
let rt = Runtime_::new().unwrap();
let rt = Runtime_::new(false).unwrap();
let cx = rt.cx();
unsafe {

Просмотреть файл

@ -30,7 +30,7 @@ fn assert_is_array(cx: *mut js::jsapi::root::JSContext,
#[test]
fn vec_conversion() {
let rt = Runtime::new().unwrap();
let rt = Runtime::new(false).unwrap();
let cx = rt.cx();
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;