diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 67e473dee43..2401b46a388 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -108,7 +108,7 @@ jobs: PYTHON3: "C:\\mozilla-build\\python3\\python3.exe" LIBCLANG_PATH: "C:\\ProgramData\\scoop\\apps\\llvm\\current\\lib" run: | - cargo test --verbose ${{ matrix.features }} --lib + cargo test --verbose ${{ matrix.features }} Integrity: runs-on: ubuntu-latest steps: diff --git a/mozjs/build.rs b/mozjs/build.rs index 38128dd582c..aa43d646dab 100644 --- a/mozjs/build.rs +++ b/mozjs/build.rs @@ -387,6 +387,7 @@ const BLACKLIST_FUNCTIONS: &'static [&'static str] = &[ "JS_GetPropertyDescriptor", "JS_GetUCPropertyDescriptor", "js::SetPropertyIgnoringNamedGetter", + "JS::FinishOffThreadStencil", ]; /// Types that should be treated as an opaque blob of bytes whenever they show diff --git a/rust-mozjs/Cargo.toml b/rust-mozjs/Cargo.toml index 9920a7e369c..c31f41a3721 100644 --- a/rust-mozjs/Cargo.toml +++ b/rust-mozjs/Cargo.toml @@ -28,6 +28,8 @@ name = "enumerate" [[test]] name = "evaluate" [[test]] +name = "offthread" +[[test]] name = "panic" [[test]] name = "property_descriptor" diff --git a/rust-mozjs/src/glue.rs b/rust-mozjs/src/glue.rs index 7485dd8d96f..6eb7460d4ee 100644 --- a/rust-mozjs/src/glue.rs +++ b/rust-mozjs/src/glue.rs @@ -1,4 +1,5 @@ use jsapi::*; +use jsapi::js::frontend::CompilationStencil; use std::os::raw::{c_char, c_void}; use std::{mem, ptr}; @@ -609,4 +610,10 @@ extern "C" { value: HandleValue, attrs: u32, ); + pub fn FinishOffThreadStencil( + cx: *mut JSContext, + token: *mut OffThreadToken, + storage: *mut InstantiationStorage, + out: *mut already_AddRefed, + ); } diff --git a/rust-mozjs/src/glue_wrappers.in b/rust-mozjs/src/glue_wrappers.in index ccb8568d309..1208d133f92 100644 --- a/rust-mozjs/src/glue_wrappers.in +++ b/rust-mozjs/src/glue_wrappers.in @@ -19,4 +19,5 @@ wrap!(glue: pub fn JS_GetPromiseResult(promise: HandleObject, dest: MutableHandl wrap!(glue: pub fn JS_GetScriptPrivate(script: *mut JSScript, dest: MutableHandleValue)); wrap!(glue: pub fn JS_GetModulePrivate(module: *mut JSObject, dest: MutableHandleValue)); wrap!(glue: pub fn EncodeStringToUTF8(cx: *mut JSContext, str: HandleString, cb: fn(*const c_char))); -wrap!(glue: pub fn SetDataPropertyDescriptor(desc: MutableHandle, value: HandleValue, attrs: u32)); \ No newline at end of file +wrap!(glue: pub fn SetDataPropertyDescriptor(desc: MutableHandle, value: HandleValue, attrs: u32)); +wrap!(glue: pub fn FinishOffThreadStencil(cx: *mut JSContext, token: *mut OffThreadToken, storage: *mut InstantiationStorage, out: *mut already_AddRefed)); diff --git a/rust-mozjs/src/jsglue.cpp b/rust-mozjs/src/jsglue.cpp index 2af60efd76f..6108333a148 100644 --- a/rust-mozjs/src/jsglue.cpp +++ b/rust-mozjs/src/jsglue.cpp @@ -28,6 +28,7 @@ #include "js/StructuredClone.h" #include "js/Wrapper.h" #include "js/experimental/JitInfo.h" +#include "js/experimental/JSStencil.h" #include "js/experimental/TypedData.h" #include "js/friend/ErrorMessages.h" #include "jsapi.h" @@ -1080,4 +1081,14 @@ void SetDataPropertyDescriptor( desc.set(JS::PropertyDescriptor::Data(value, attrs)); } +void FinishOffThreadStencil( + JSContext* cx, + JS::OffThreadToken* token, + JS::InstantiationStorage* storage, + already_AddRefed* stencil +) { + already_AddRefed retval = JS::FinishOffThreadStencil(cx, token, storage); + *stencil = std::move(retval); +} + } // extern "C" diff --git a/rust-mozjs/src/rust.rs b/rust-mozjs/src/rust.rs index 2cf4f03a7cf..302201ac2dd 100644 --- a/rust-mozjs/src/rust.rs +++ b/rust-mozjs/src/rust.rs @@ -976,7 +976,11 @@ pub unsafe fn FinishOffThreadStencil( token: *mut OffThreadToken, storage: *mut InstantiationStorage, ) -> Stencil { - let stencil = jsapi::FinishOffThreadStencil(cx, token, storage); + let mut stencil = already_AddRefed { + mRawPtr: std::ptr::null_mut(), + _phantom_0: PhantomData, + }; + crate::glue::FinishOffThreadStencil(cx, token, storage, &mut stencil); return Stencil { inner: stencil }; } diff --git a/rust-mozjs/tests/offthread.rs b/rust-mozjs/tests/offthread.rs new file mode 100644 index 00000000000..1c06b0c2b34 --- /dev/null +++ b/rust-mozjs/tests/offthread.rs @@ -0,0 +1,101 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#[macro_use] +extern crate mozjs; + +use std::os::raw::c_void; +use std::ptr; +use std::sync::mpsc::{channel, Sender}; + +use mozjs::jsapi::{ + JS_NewGlobalObject, OnNewGlobalHookOption, OffThreadToken, CanCompileOffThread, + CompileToStencilOffThread1, InstantiateOptions, InstantiateGlobalStencil, JSAutoRealm, +}; +use mozjs::jsval::UndefinedValue; +use mozjs::rust::{ + JSEngine, RealmOptions, Runtime, SIMPLE_GLOBAL_CLASS, CompileOptionsWrapper, + transform_str_to_source_text, FinishOffThreadStencil, wrappers::JS_ExecuteScript +}; + +struct Token(*mut OffThreadToken); + +unsafe impl Send for Token {} + +struct Context { + text: String, + sender: Sender, +} + +unsafe extern "C" fn callback( + token: *mut OffThreadToken, + callback_data: *mut c_void, +) { + let context = Box::from_raw(callback_data as *mut Context); + let token = Token(token); + context.sender.send(token).unwrap(); +} + +#[test] +fn evaluate() { + let engine = JSEngine::init().unwrap(); + let runtime = Runtime::new(engine.handle()); + let context = runtime.cx(); + let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook; + let c_option = RealmOptions::default(); + + unsafe { + rooted!(in(context) let global = JS_NewGlobalObject( + context, + &SIMPLE_GLOBAL_CLASS, + ptr::null_mut(), + h_option, + &*c_option, + )); + + let _ac = JSAutoRealm::new(context, global.get()); + + let src = "1 + 1".to_string(); + let mut options = CompileOptionsWrapper::new(context, "", 1); + (*options.ptr)._base.forceAsync = true; + let options_ptr = options.ptr as *const _; + assert!(CanCompileOffThread(context, options_ptr, src.len())); + let (sender, receiver) = channel(); + let script_context = Box::new(Context { + text: src, + sender, + }); + assert!(!CompileToStencilOffThread1( + context, + options_ptr, + &mut transform_str_to_source_text(&script_context.text) as *mut _, + Some(callback), + Box::into_raw(script_context) as *mut c_void, + ).is_null()); + + let token = receiver.recv().unwrap(); + let compiled_script = FinishOffThreadStencil(context, token.0, ptr::null_mut()); + assert!(!compiled_script.is_null()); + + let options = InstantiateOptions { + skipFilenameValidation: false, + hideScriptFromDebugger: false, + deferDebugMetadata: false, + }; + rooted!(in(context) let script = InstantiateGlobalStencil( + context, + &options, + *compiled_script, + ptr::null_mut(), + )); + + rooted!(in(context) let mut rval = UndefinedValue()); + let result = JS_ExecuteScript(context, script.handle(), rval.handle_mut()); + assert!(result); + /*assert!(runtime + .evaluate_script(global.handle(), "1 + 1", "test", 1, rval.handle_mut()) + .is_ok());*/ + assert_eq!(rval.get().to_int32(), 2); + } +}