0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2025-01-11 08:34:01 -05:00

Add support for Platform::pump_message_loop and Platform::run_idle_tasks (#706)

Co-authored-by: Ben Noordhuis <info@bnoordhuis.nl>
This commit is contained in:
Tim Ramlot 2021-07-01 16:05:07 +02:00 committed by GitHub
parent 89c8ae8af3
commit 14bcf04bef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 346 additions and 58 deletions

View file

@ -2,7 +2,7 @@ use rusty_v8 as v8;
fn main() {
// Initialize V8.
let platform = v8::new_default_platform().unwrap();
let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();

View file

@ -19,7 +19,7 @@ fn log_callback(
fn main() {
// Initialize V8.
let platform = v8::new_default_platform().unwrap();
let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();

View file

@ -2,7 +2,7 @@ use rusty_v8 as v8;
fn main() {
// Initialize V8.
let platform = v8::new_default_platform().unwrap();
let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();
@ -79,11 +79,15 @@ fn run_main(
let script: &str = &args[i + 1];
skip_next = true;
// TODO: pump event loop (not implemented on rusty_v8?)
// while v8::Platform::pump_message_loop(&platform, isolate) {
// // do nothing
// }
execute_string(scope, script, "unnamed", false, true);
while v8::Platform::pump_message_loop(
&v8::V8::get_current_platform(),
scope,
false,
) {
// do nothing
}
}
arg => {
if arg.starts_with("--") {
@ -94,6 +98,14 @@ fn run_main(
// Use all other arguments as names of files to load and run.
let script = std::fs::read_to_string(arg).expect("failed to read file");
execute_string(scope, &script, arg, false, true);
while v8::Platform::pump_message_loop(
&v8::V8::get_current_platform(),
scope,
false,
) {
// do nothing
}
}
}
}

View file

@ -7,7 +7,7 @@ use std::sync::Mutex;
use std::vec::Vec;
use crate::platform::Platform;
use crate::support::UniqueRef;
use crate::support::SharedRef;
use crate::support::UnitType;
extern "C" {
@ -61,24 +61,26 @@ where
}
}
#[derive(Debug, Eq, PartialEq)]
#[derive(Debug)]
enum GlobalState {
Uninitialized,
PlatformInitialized,
Initialized,
Disposed,
PlatformInitialized(SharedRef<Platform>),
Initialized(SharedRef<Platform>),
Disposed(SharedRef<Platform>),
PlatformShutdown,
}
use GlobalState::*;
lazy_static! {
static ref GLOBAL_STATE: Mutex<GlobalState> =
Mutex::new(GlobalState::Uninitialized);
static ref GLOBAL_STATE: Mutex<GlobalState> = Mutex::new(Uninitialized);
}
pub fn assert_initialized() {
let global_state_guard = GLOBAL_STATE.lock().unwrap();
assert_eq!(*global_state_guard, Initialized);
match *global_state_guard {
Initialized(_) => {}
_ => panic!("Invalid global state"),
};
}
/// Pass the command line arguments to v8.
@ -173,25 +175,41 @@ pub fn get_version() -> &'static str {
c_str.to_str().unwrap()
}
// TODO: V8::InitializePlatform does not actually take a UniquePtr but rather
// a raw pointer. This means that the Platform object is not released when
// V8::ShutdownPlatform is called.
/// Sets the v8::Platform to use. This should be invoked before V8 is
/// initialized.
pub fn initialize_platform(platform: UniqueRef<Platform>) {
pub fn initialize_platform(platform: SharedRef<Platform>) {
let mut global_state_guard = GLOBAL_STATE.lock().unwrap();
assert_eq!(*global_state_guard, Uninitialized);
unsafe { v8__V8__InitializePlatform(platform.into_raw()) };
*global_state_guard = PlatformInitialized;
*global_state_guard = match *global_state_guard {
Uninitialized => PlatformInitialized(platform.clone()),
_ => panic!("Invalid global state"),
};
{
unsafe {
v8__V8__InitializePlatform(&*platform as *const Platform as *mut _)
};
}
}
/// Initializes V8. This function needs to be called before the first Isolate
/// is created. It always returns true.
pub fn initialize() {
let mut global_state_guard = GLOBAL_STATE.lock().unwrap();
assert_eq!(*global_state_guard, PlatformInitialized);
unsafe { v8__V8__Initialize() };
*global_state_guard = Initialized;
*global_state_guard = match *global_state_guard {
PlatformInitialized(ref platform) => Initialized(platform.clone()),
_ => panic!("Invalid global state"),
};
unsafe { v8__V8__Initialize() }
}
/// Sets the v8::Platform to use. This should be invoked before V8 is
/// initialized.
pub fn get_current_platform() -> SharedRef<Platform> {
let global_state_guard = GLOBAL_STATE.lock().unwrap();
match *global_state_guard {
Initialized(ref platform) => platform.clone(),
_ => panic!("Invalid global state"),
}
}
/// Releases any resources used by v8 and stops any utility threads
@ -208,9 +226,11 @@ pub fn initialize() {
/// to a crash.
pub unsafe fn dispose() -> bool {
let mut global_state_guard = GLOBAL_STATE.lock().unwrap();
assert_eq!(*global_state_guard, Initialized);
*global_state_guard = match *global_state_guard {
Initialized(ref platform) => Disposed(platform.clone()),
_ => panic!("Invalid global state"),
};
assert!(v8__V8__Dispose());
*global_state_guard = Disposed;
true
}
@ -218,7 +238,10 @@ pub unsafe fn dispose() -> bool {
/// V8 was disposed.
pub fn shutdown_platform() {
let mut global_state_guard = GLOBAL_STATE.lock().unwrap();
assert_eq!(*global_state_guard, Disposed);
// First shutdown platform, then drop platform
unsafe { v8__V8__ShutdownPlatform() };
*global_state_guard = PlatformShutdown;
*global_state_guard = match *global_state_guard {
Disposed(_) => PlatformShutdown,
_ => panic!("Invalid global state"),
};
}

View file

@ -2028,18 +2028,64 @@ v8::StartupData v8__SnapshotCreator__CreateBlob(
return self->CreateBlob(function_code_handling);
}
v8::Platform* v8__platform__NewDefaultPlatform() {
// TODO(bnoordhuis) Support optional arguments.
return v8::platform::NewDefaultPlatform().release();
v8::Platform* v8__Platform__NewDefaultPlatform(int thread_pool_size,
bool idle_task_support) {
return v8::platform::NewDefaultPlatform(
thread_pool_size,
idle_task_support ? v8::platform::IdleTaskSupport::kEnabled
: v8::platform::IdleTaskSupport::kDisabled,
v8::platform::InProcessStackDumping::kDisabled, nullptr)
.release();
}
v8::Platform* v8__platform__NewSingleThreadedDefaultPlatform() {
// TODO(bnoordhuis) Support optional arguments.
return v8::platform::NewSingleThreadedDefaultPlatform().release();
v8::Platform* v8__Platform__NewSingleThreadedDefaultPlatform(
bool idle_task_support) {
return v8::platform::NewSingleThreadedDefaultPlatform(
idle_task_support ? v8::platform::IdleTaskSupport::kEnabled
: v8::platform::IdleTaskSupport::kDisabled,
v8::platform::InProcessStackDumping::kDisabled, nullptr)
.release();
}
bool v8__Platform__PumpMessageLoop(v8::Platform* platform, v8::Isolate* isolate,
bool wait_for_work) {
return v8::platform::PumpMessageLoop(
platform, isolate,
wait_for_work ? v8::platform::MessageLoopBehavior::kWaitForWork
: v8::platform::MessageLoopBehavior::kDoNotWait);
}
void v8__Platform__RunIdleTasks(v8::Platform* platform, v8::Isolate* isolate,
double idle_time_in_seconds) {
v8::platform::RunIdleTasks(platform, isolate, idle_time_in_seconds);
}
void v8__Platform__DELETE(v8::Platform* self) { delete self; }
two_pointers_t std__shared_ptr__v8__Platform__CONVERT__std__unique_ptr(
v8::Platform* unique_ptr) {
return make_pod<two_pointers_t>(std::shared_ptr<v8::Platform>(unique_ptr));
}
v8::Platform* std__shared_ptr__v8__Platform__get(
const std::shared_ptr<v8::Platform>& ptr) {
return ptr.get();
}
two_pointers_t std__shared_ptr__v8__Platform__COPY(
const std::shared_ptr<v8::Platform>& ptr) {
return make_pod<two_pointers_t>(ptr);
}
void std__shared_ptr__v8__Platform__reset(std::shared_ptr<v8::Platform>* ptr) {
ptr->reset();
}
long std__shared_ptr__v8__Platform__use_count(
const std::shared_ptr<v8::Platform>& ptr) {
return ptr.use_count();
}
void v8_inspector__V8Inspector__Channel__BASE__sendResponse(
v8_inspector::V8Inspector::Channel* self, int callId,
v8_inspector::StringBuffer* message);

View file

@ -5,7 +5,7 @@
//! ```rust
//! use rusty_v8 as v8;
//!
//! let platform = v8::new_default_platform().unwrap();
//! let platform = v8::new_default_platform(0, false).make_shared();
//! v8::V8::initialize_platform(platform);
//! v8::V8::initialize();
//!

View file

@ -1,31 +1,181 @@
use crate::support::int;
use crate::Isolate;
use crate::support::long;
use crate::support::Opaque;
use crate::support::Shared;
use crate::support::SharedPtrBase;
use crate::support::SharedRef;
use crate::support::UniquePtr;
use crate::support::UniqueRef;
extern "C" {
fn v8__platform__NewDefaultPlatform() -> *mut Platform;
fn v8__platform__NewSingleThreadedDefaultPlatform() -> *mut Platform;
fn v8__Platform__NewDefaultPlatform(
thread_pool_size: int,
idle_task_support: bool,
) -> *mut Platform;
fn v8__Platform__NewSingleThreadedDefaultPlatform(
idle_task_support: bool,
) -> *mut Platform;
fn v8__Platform__DELETE(this: *mut Platform);
}
/// Returns a new instance of the default v8::Platform implementation.
pub fn new_default_platform() -> UniquePtr<Platform> {
unsafe { UniquePtr::from_raw(v8__platform__NewDefaultPlatform()) }
}
fn v8__Platform__PumpMessageLoop(
platform: *mut Platform,
isolate: *mut Isolate,
wait_for_work: bool,
) -> bool;
/// The same as new_default_platform() but disables the worker thread pool.
/// It must be used with the --single-threaded V8 flag.
pub fn new_single_threaded_default_platform() -> UniquePtr<Platform> {
unsafe {
UniquePtr::from_raw(v8__platform__NewSingleThreadedDefaultPlatform())
}
fn v8__Platform__RunIdleTasks(
platform: *mut Platform,
isolate: *mut Isolate,
idle_time_in_seconds: f64,
);
fn std__shared_ptr__v8__Platform__CONVERT__std__unique_ptr(
unique_ptr: UniquePtr<Platform>,
) -> SharedPtrBase<Platform>;
fn std__shared_ptr__v8__Platform__get(
ptr: *const SharedPtrBase<Platform>,
) -> *mut Platform;
fn std__shared_ptr__v8__Platform__COPY(
ptr: *const SharedPtrBase<Platform>,
) -> SharedPtrBase<Platform>;
fn std__shared_ptr__v8__Platform__reset(ptr: *mut SharedPtrBase<Platform>);
fn std__shared_ptr__v8__Platform__use_count(
ptr: *const SharedPtrBase<Platform>,
) -> long;
}
#[repr(C)]
#[derive(Debug)]
pub struct Platform(Opaque);
impl Drop for Platform {
fn drop(&mut self) {
unsafe { v8__Platform__DELETE(self) }
/// Returns a new instance of the default v8::Platform implementation.
///
/// |thread_pool_size| is the number of worker threads to allocate for
/// background jobs. If a value of zero is passed, a suitable default
/// based on the current number of processors online will be chosen.
/// If |idle_task_support| is enabled then the platform will accept idle
/// tasks (IdleTasksEnabled will return true) and will rely on the embedder
/// calling v8::platform::RunIdleTasks to process the idle tasks.
pub fn new_default_platform(
thread_pool_size: u32,
idle_task_support: bool,
) -> UniqueRef<Platform> {
Platform::new(thread_pool_size, idle_task_support)
}
/// The same as new_default_platform() but disables the worker thread pool.
/// It must be used with the --single-threaded V8 flag.
///
/// If |idle_task_support| is enabled then the platform will accept idle
/// tasks (IdleTasksEnabled will return true) and will rely on the embedder
/// calling v8::platform::RunIdleTasks to process the idle tasks.
pub fn new_single_threaded_default_platform(
idle_task_support: bool,
) -> UniqueRef<Platform> {
Platform::new_single_threaded(idle_task_support)
}
impl Platform {
/// Returns a new instance of the default v8::Platform implementation.
///
/// |thread_pool_size| is the number of worker threads to allocate for
/// background jobs. If a value of zero is passed, a suitable default
/// based on the current number of processors online will be chosen.
/// If |idle_task_support| is enabled then the platform will accept idle
/// tasks (IdleTasksEnabled will return true) and will rely on the embedder
/// calling v8::platform::RunIdleTasks to process the idle tasks.
pub fn new(
thread_pool_size: u32,
idle_task_support: bool,
) -> UniqueRef<Self> {
unsafe {
UniqueRef::from_raw(v8__Platform__NewDefaultPlatform(
thread_pool_size.min(16) as i32,
idle_task_support,
))
}
}
/// The same as new() but disables the worker thread pool.
/// It must be used with the --single-threaded V8 flag.
///
/// If |idle_task_support| is enabled then the platform will accept idle
/// tasks (IdleTasksEnabled will return true) and will rely on the embedder
/// calling v8::platform::RunIdleTasks to process the idle tasks.
pub fn new_single_threaded(idle_task_support: bool) -> UniqueRef<Self> {
unsafe {
UniqueRef::from_raw(v8__Platform__NewSingleThreadedDefaultPlatform(
idle_task_support,
))
}
}
}
impl Platform {
/// Pumps the message loop for the given isolate.
///
/// The caller has to make sure that this is called from the right thread.
/// Returns true if a task was executed, and false otherwise. If the call to
/// PumpMessageLoop is nested within another call to PumpMessageLoop, only
/// nestable tasks may run. Otherwise, any task may run. Unless requested through
/// the |wait_for_work| parameter, this call does not block if no task is pending.
pub fn pump_message_loop(
platform: &SharedRef<Self>,
isolate: &mut Isolate,
wait_for_work: bool,
) -> bool {
unsafe {
v8__Platform__PumpMessageLoop(
&**platform as *const Self as *mut _,
isolate,
wait_for_work,
)
}
}
/// Runs pending idle tasks for at most |idle_time_in_seconds| seconds.
///
/// The caller has to make sure that this is called from the right thread.
/// This call does not block if no task is pending.
pub fn run_idle_tasks(
platform: &SharedRef<Self>,
isolate: &mut Isolate,
idle_time_in_seconds: f64,
) {
unsafe {
v8__Platform__RunIdleTasks(
&**platform as *const Self as *mut _,
isolate,
idle_time_in_seconds,
)
}
}
}
impl Shared for Platform {
fn from_unique_ptr(unique_ptr: UniquePtr<Self>) -> SharedPtrBase<Self> {
unsafe {
std__shared_ptr__v8__Platform__CONVERT__std__unique_ptr(unique_ptr)
}
}
fn get(ptr: &SharedPtrBase<Self>) -> *const Self {
unsafe { std__shared_ptr__v8__Platform__get(ptr) }
}
fn clone(ptr: &SharedPtrBase<Self>) -> SharedPtrBase<Self> {
unsafe { std__shared_ptr__v8__Platform__COPY(ptr) }
}
fn reset(ptr: &mut SharedPtrBase<Self>) {
unsafe { std__shared_ptr__v8__Platform__reset(ptr) }
}
fn use_count(ptr: &SharedPtrBase<Self>) -> long {
unsafe { std__shared_ptr__v8__Platform__use_count(ptr) }
}
}
impl Drop for Platform {
fn drop(&mut self) {
unsafe { v8__Platform__DELETE(self) };
}
}

View file

@ -1727,7 +1727,7 @@ mod tests {
fn initialize_v8() {
static INIT: Once = Once::new();
INIT.call_once(|| {
V8::initialize_platform(new_default_platform().unwrap());
V8::initialize_platform(new_default_platform(0, false).make_shared());
V8::initialize();
});
}

View file

@ -28,7 +28,9 @@ impl CoreIsolate {
fn new(drop_count: Rc<AtomicUsize>) -> CoreIsolate {
static START: Once = Once::new();
START.call_once(|| {
v8::V8::initialize_platform(v8::new_default_platform().unwrap());
v8::V8::initialize_platform(
v8::new_default_platform(0, false).make_shared(),
);
v8::V8::initialize();
});
let mut isolate = v8::Isolate::new(Default::default());

View file

@ -31,7 +31,9 @@ fn setup() -> SetupGuard {
))
.is_ok());
v8::V8::set_flags_from_string("--expose_gc --harmony-import-assertions");
v8::V8::initialize_platform(v8::new_default_platform().unwrap());
v8::V8::initialize_platform(
v8::new_default_platform(0, false).make_shared(),
);
v8::V8::initialize();
});
SetupGuard {}

View file

@ -19,7 +19,7 @@ fn set_entropy_source() {
true
});
v8::V8::initialize_platform(v8::new_default_platform().unwrap());
v8::V8::initialize_platform(v8::new_default_platform(0, false).make_shared());
v8::V8::initialize();
// Assumes that every isolate creates a PRNG from scratch, which is currently true.

View file

@ -5,7 +5,7 @@ use rusty_v8 as v8;
#[test]
fn set_flags_from_string() {
v8::V8::set_flags_from_string("--use_strict");
v8::V8::initialize_platform(v8::new_default_platform().unwrap());
v8::V8::initialize_platform(v8::new_default_platform(0, false).make_shared());
v8::V8::initialize();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);

View file

@ -0,0 +1,53 @@
use rusty_v8 as v8;
#[test]
fn atomics_pump_message_loop() {
v8::V8::set_flags_from_string("--harmony-top-level-await --allow-natives-syntax --harmony-sharedarraybuffer");
v8::V8::initialize_platform(v8::new_default_platform(0, false).make_shared());
v8::V8::initialize();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let scope = &mut v8::ContextScope::new(scope, context);
let source = r#"
function assertEquals(a, b) {
if (a === b) return;
throw a + " does not equal " + b;
}
const sab = new SharedArrayBuffer(16);
const i32a = new Int32Array(sab);
let resolved = false;
(function() {
const result = Atomics.waitAsync(i32a, 0, 0);
result.value.then(
(value) => { assertEquals("ok", value); resolved = true; },
() => { assertUnreachable();
});
})();
const notify_return_value = Atomics.notify(i32a, 0, 1);
assertEquals(1, notify_return_value);
assertEquals(0, %AtomicsNumWaitersForTesting(i32a, 0));
assertEquals(1, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
"#;
let source = v8::String::new(scope, source).unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();
script.run(scope).unwrap();
while v8::Platform::pump_message_loop(
&v8::V8::get_current_platform(),
scope,
false,
) {
// do nothing
}
let source2 = r#"
assertEquals(0, %AtomicsNumUnresolvedAsyncPromisesForTesting(i32a, 0));
"#;
let source2 = v8::String::new(scope, source2).unwrap();
let script2 = v8::Script::compile(scope, source2, None).unwrap();
script2.run(scope).unwrap();
}

View file

@ -4,7 +4,7 @@ use rusty_v8 as v8;
fn single_threaded_default_platform() {
v8::V8::set_flags_from_string("--single_threaded");
v8::V8::initialize_platform(
v8::new_single_threaded_default_platform().unwrap(),
v8::new_single_threaded_default_platform(false).make_shared(),
);
v8::V8::initialize();