mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-26 00:59:28 -05:00
6b2c7a56a7
Isolate::run_microtasks() already exists but the microtasks queue is also flushed on script entry and exit. Some embedders want strict control over when microtasks run, which is set by the policy. And deprecate Isolate::run_microtasks(). The corresponding V8 API is tagged with V8_DEPRECATE_SOON.
163 lines
4.3 KiB
Rust
163 lines
4.3 KiB
Rust
// These tests mock out an organizational pattern that we hope to use in Deno.
|
|
// There we want to wrap v8::Isolate to provide extra functionality at multiple
|
|
// layers: v8::Isolate -> CoreIsolate -> EsIsolate
|
|
// This demonstrates how this can be done in a safe way.
|
|
|
|
use rusty_v8 as v8;
|
|
use std::ops::Deref;
|
|
use std::ops::DerefMut;
|
|
use std::rc::Rc;
|
|
use std::sync::atomic::AtomicUsize;
|
|
use std::sync::atomic::Ordering;
|
|
use std::sync::Once;
|
|
|
|
struct CoreIsolate(v8::OwnedIsolate);
|
|
|
|
struct CoreIsolateState {
|
|
drop_count: Rc<AtomicUsize>,
|
|
i: usize,
|
|
}
|
|
|
|
impl Drop for CoreIsolateState {
|
|
fn drop(&mut self) {
|
|
self.drop_count.fetch_add(1, Ordering::SeqCst);
|
|
}
|
|
}
|
|
|
|
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();
|
|
});
|
|
let mut isolate = v8::Isolate::new(Default::default());
|
|
let state = CoreIsolateState { drop_count, i: 0 };
|
|
isolate.set_slot(state);
|
|
CoreIsolate(isolate)
|
|
}
|
|
|
|
// Returns false if there was an error.
|
|
fn execute(&mut self, code: &str) -> bool {
|
|
let scope = &mut v8::HandleScope::new(&mut self.0);
|
|
let context = v8::Context::new(scope);
|
|
let scope = &mut v8::ContextScope::new(scope, context);
|
|
let source = v8::String::new(scope, code).unwrap();
|
|
let script = v8::Script::compile(scope, source, None).unwrap();
|
|
let r = script.run(scope);
|
|
r.is_some()
|
|
}
|
|
|
|
fn get_i(&self) -> usize {
|
|
let s = self.0.get_slot::<CoreIsolateState>().unwrap();
|
|
s.i
|
|
}
|
|
|
|
fn set_i(&self, i: usize) {
|
|
let mut s = self.0.get_slot_mut::<CoreIsolateState>().unwrap();
|
|
s.i = i;
|
|
}
|
|
}
|
|
|
|
impl Deref for CoreIsolate {
|
|
type Target = v8::Isolate;
|
|
|
|
fn deref(&self) -> &v8::Isolate {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl DerefMut for CoreIsolate {
|
|
fn deref_mut(&mut self) -> &mut v8::Isolate {
|
|
&mut self.0
|
|
}
|
|
}
|
|
|
|
struct EsIsolate(CoreIsolate);
|
|
|
|
struct EsIsolateState {
|
|
drop_count: Rc<AtomicUsize>,
|
|
x: bool,
|
|
}
|
|
|
|
impl Drop for EsIsolateState {
|
|
fn drop(&mut self) {
|
|
self.drop_count.fetch_add(1, Ordering::SeqCst);
|
|
}
|
|
}
|
|
|
|
impl EsIsolate {
|
|
fn new(drop_count: Rc<AtomicUsize>) -> Self {
|
|
let mut core_isolate = CoreIsolate::new(drop_count.clone());
|
|
let state = EsIsolateState {
|
|
drop_count,
|
|
x: false,
|
|
};
|
|
core_isolate.set_slot(state);
|
|
EsIsolate(core_isolate)
|
|
}
|
|
|
|
fn get_x(&self) -> bool {
|
|
let state = self.0.get_slot::<EsIsolateState>().unwrap();
|
|
state.x
|
|
}
|
|
|
|
fn set_x(&self, x: bool) {
|
|
let mut state = self.0.get_slot_mut::<EsIsolateState>().unwrap();
|
|
state.x = x;
|
|
}
|
|
}
|
|
|
|
impl Deref for EsIsolate {
|
|
type Target = CoreIsolate;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl DerefMut for EsIsolate {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.0
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn slots_layer1() {
|
|
let drop_count = Rc::new(AtomicUsize::new(0));
|
|
let mut core_isolate = CoreIsolate::new(drop_count.clone());
|
|
// The existence of a IsolateHandle that outlives the isolate should not
|
|
// inhibit dropping of slot contents.
|
|
let isolate_handle = core_isolate.thread_safe_handle();
|
|
assert!(core_isolate.execute("1 + 1"));
|
|
assert!(!core_isolate.execute("throw 'foo'"));
|
|
assert_eq!(0, core_isolate.get_i());
|
|
core_isolate.set_i(123);
|
|
assert_eq!(123, core_isolate.get_i());
|
|
assert_eq!(drop_count.load(Ordering::SeqCst), 0);
|
|
// Check that we can deref CoreIsolate by running a random v8::Isolate method
|
|
core_isolate.perform_microtask_checkpoint();
|
|
drop(core_isolate);
|
|
assert_eq!(drop_count.load(Ordering::SeqCst), 1);
|
|
drop(isolate_handle);
|
|
}
|
|
|
|
#[test]
|
|
fn slots_layer2() {
|
|
let drop_count = Rc::new(AtomicUsize::new(0));
|
|
let mut es_isolate = EsIsolate::new(drop_count.clone());
|
|
// We can deref to CoreIsolate and use execute...
|
|
assert!(es_isolate.execute("1 + 1"));
|
|
assert!(!es_isolate.execute("throw 'bar'"));
|
|
// We can use get_x set_x
|
|
assert!(!es_isolate.get_x());
|
|
es_isolate.set_x(true);
|
|
assert!(es_isolate.get_x());
|
|
// Check that we can deref all the way to a v8::Isolate method
|
|
es_isolate.perform_microtask_checkpoint();
|
|
|
|
// When we drop, both CoreIsolateState and EsIsolateState should be dropped.
|
|
assert_eq!(drop_count.load(Ordering::SeqCst), 0);
|
|
drop(es_isolate);
|
|
assert_eq!(drop_count.load(Ordering::SeqCst), 2);
|
|
}
|