mirror of
https://github.com/denoland/rusty_v8.git
synced 2025-03-09 13:38:51 -04:00
ShadowRealm
integration callback (#959)
This commit is contained in:
parent
5f90045ad0
commit
d43535c48b
4 changed files with 159 additions and 1 deletions
|
@ -4,6 +4,7 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "support.h"
|
#include "support.h"
|
||||||
|
#include "v8-callbacks.h"
|
||||||
#include "v8/include/libplatform/libplatform.h"
|
#include "v8/include/libplatform/libplatform.h"
|
||||||
#include "v8/include/v8-fast-api-calls.h"
|
#include "v8/include/v8-fast-api-calls.h"
|
||||||
#include "v8/include/v8-inspector.h"
|
#include "v8/include/v8-inspector.h"
|
||||||
|
@ -263,6 +264,11 @@ void v8__Isolate__SetHostImportModuleDynamicallyCallback(
|
||||||
HostImportModuleDynamicallyCallback);
|
HostImportModuleDynamicallyCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void v8__Isolate__SetHostCreateShadowRealmContextCallback(
|
||||||
|
v8::Isolate* isolate, v8::HostCreateShadowRealmContextCallback callback) {
|
||||||
|
isolate->SetHostCreateShadowRealmContextCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
bool v8__Isolate__AddMessageListener(v8::Isolate* isolate,
|
bool v8__Isolate__AddMessageListener(v8::Isolate* isolate,
|
||||||
v8::MessageCallback callback) {
|
v8::MessageCallback callback) {
|
||||||
return isolate->AddMessageListener(callback);
|
return isolate->AddMessageListener(callback);
|
||||||
|
|
|
@ -129,6 +129,19 @@ pub type HostImportModuleDynamicallyCallback = extern "C" fn(
|
||||||
Local<FixedArray>,
|
Local<FixedArray>,
|
||||||
) -> *mut Promise;
|
) -> *mut Promise;
|
||||||
|
|
||||||
|
/// `HostCreateShadowRealmContextCallback` is called each time a `ShadowRealm`
|
||||||
|
/// is being constructed. You can use [`HandleScope::get_current_context`] to
|
||||||
|
/// get the [`Context`] in which the constructor is being run.
|
||||||
|
///
|
||||||
|
/// The method combines [`Context`] creation and the implementation-defined
|
||||||
|
/// abstract operation `HostInitializeShadowRealm` into one.
|
||||||
|
///
|
||||||
|
/// The embedder should use [`Context::new`] to create a new context. If the
|
||||||
|
/// creation fails, the embedder must propagate that exception by returning
|
||||||
|
/// [`None`].
|
||||||
|
pub type HostCreateShadowRealmContextCallback =
|
||||||
|
for<'s> fn(scope: &mut HandleScope<'s>) -> Option<Local<'s, Context>>;
|
||||||
|
|
||||||
pub type InterruptCallback =
|
pub type InterruptCallback =
|
||||||
extern "C" fn(isolate: &mut Isolate, data: *mut c_void);
|
extern "C" fn(isolate: &mut Isolate, data: *mut c_void);
|
||||||
|
|
||||||
|
@ -222,6 +235,19 @@ extern "C" {
|
||||||
isolate: *mut Isolate,
|
isolate: *mut Isolate,
|
||||||
callback: HostImportModuleDynamicallyCallback,
|
callback: HostImportModuleDynamicallyCallback,
|
||||||
);
|
);
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
fn v8__Isolate__SetHostCreateShadowRealmContextCallback(
|
||||||
|
isolate: *mut Isolate,
|
||||||
|
callback: extern "C" fn(initiator_context: Local<Context>) -> *mut Context,
|
||||||
|
);
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn v8__Isolate__SetHostCreateShadowRealmContextCallback(
|
||||||
|
isolate: *mut Isolate,
|
||||||
|
callback: extern "C" fn(
|
||||||
|
rv: *mut *mut Context,
|
||||||
|
initiator_context: Local<Context>,
|
||||||
|
) -> *mut *mut Context,
|
||||||
|
);
|
||||||
fn v8__Isolate__RequestInterrupt(
|
fn v8__Isolate__RequestInterrupt(
|
||||||
isolate: *const Isolate,
|
isolate: *const Isolate,
|
||||||
callback: InterruptCallback,
|
callback: InterruptCallback,
|
||||||
|
@ -609,6 +635,56 @@ impl Isolate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This specifies the callback called by the upcoming `ShadowRealm`
|
||||||
|
/// construction language feature to retrieve host created globals.
|
||||||
|
pub fn set_host_create_shadow_realm_context_callback(
|
||||||
|
&mut self,
|
||||||
|
callback: HostCreateShadowRealmContextCallback,
|
||||||
|
) {
|
||||||
|
#[inline]
|
||||||
|
extern "C" fn rust_shadow_realm_callback(
|
||||||
|
initiator_context: Local<Context>,
|
||||||
|
) -> *mut Context {
|
||||||
|
let mut scope = unsafe { CallbackScope::new(initiator_context) };
|
||||||
|
let callback = scope
|
||||||
|
.get_slot::<HostCreateShadowRealmContextCallback>()
|
||||||
|
.unwrap();
|
||||||
|
let context = callback(&mut scope);
|
||||||
|
context
|
||||||
|
.map(|l| l.as_non_null().as_ptr())
|
||||||
|
.unwrap_or_else(null_mut)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Windows x64 ABI: MaybeLocal<Context> must be returned on the stack.
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
extern "C" fn rust_shadow_realm_callback_windows(
|
||||||
|
rv: *mut *mut Context,
|
||||||
|
initiator_context: Local<Context>,
|
||||||
|
) -> *mut *mut Context {
|
||||||
|
let ret = rust_shadow_realm_callback(initiator_context);
|
||||||
|
unsafe {
|
||||||
|
rv.write(ret);
|
||||||
|
}
|
||||||
|
rv
|
||||||
|
}
|
||||||
|
|
||||||
|
let slot_didnt_exist_before = self.set_slot(callback);
|
||||||
|
if slot_didnt_exist_before {
|
||||||
|
unsafe {
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
v8__Isolate__SetHostCreateShadowRealmContextCallback(
|
||||||
|
self,
|
||||||
|
rust_shadow_realm_callback_windows,
|
||||||
|
);
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
v8__Isolate__SetHostCreateShadowRealmContextCallback(
|
||||||
|
self,
|
||||||
|
rust_shadow_realm_callback,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Add a callback to invoke in case the heap size is close to the heap limit.
|
/// Add a callback to invoke in case the heap size is close to the heap limit.
|
||||||
/// If multiple callbacks are added, only the most recently added callback is
|
/// If multiple callbacks are added, only the most recently added callback is
|
||||||
/// invoked.
|
/// invoked.
|
||||||
|
|
|
@ -92,6 +92,7 @@ pub use handle::Handle;
|
||||||
pub use handle::Local;
|
pub use handle::Local;
|
||||||
pub use handle::Weak;
|
pub use handle::Weak;
|
||||||
pub use isolate::HeapStatistics;
|
pub use isolate::HeapStatistics;
|
||||||
|
pub use isolate::HostCreateShadowRealmContextCallback;
|
||||||
pub use isolate::HostImportModuleDynamicallyCallback;
|
pub use isolate::HostImportModuleDynamicallyCallback;
|
||||||
pub use isolate::HostInitializeImportMetaObjectCallback;
|
pub use isolate::HostInitializeImportMetaObjectCallback;
|
||||||
pub use isolate::Isolate;
|
pub use isolate::Isolate;
|
||||||
|
|
|
@ -35,7 +35,9 @@ fn setup() -> SetupGuard {
|
||||||
"../third_party/icu/common/icudtl.dat"
|
"../third_party/icu/common/icudtl.dat"
|
||||||
))
|
))
|
||||||
.is_ok());
|
.is_ok());
|
||||||
v8::V8::set_flags_from_string("--expose_gc --harmony-import-assertions");
|
v8::V8::set_flags_from_string(
|
||||||
|
"--expose_gc --harmony-import-assertions --harmony-shadow-realm",
|
||||||
|
);
|
||||||
v8::V8::initialize_platform(
|
v8::V8::initialize_platform(
|
||||||
v8::new_default_platform(0, false).make_shared(),
|
v8::new_default_platform(0, false).make_shared(),
|
||||||
);
|
);
|
||||||
|
@ -6728,3 +6730,76 @@ fn finalizer_on_kept_global() {
|
||||||
drop(weak);
|
drop(weak);
|
||||||
drop(global);
|
drop(global);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn host_create_shadow_realm_context_callback() {
|
||||||
|
let _setup_guard = setup();
|
||||||
|
|
||||||
|
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 tc_scope = &mut v8::TryCatch::new(scope);
|
||||||
|
assert!(eval(tc_scope, "new ShadowRealm()").is_none());
|
||||||
|
assert!(tc_scope.has_caught());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CheckData {
|
||||||
|
callback_called: bool,
|
||||||
|
main_context: v8::Global<v8::Context>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let main_context = v8::Global::new(scope, context);
|
||||||
|
scope.set_slot(CheckData {
|
||||||
|
callback_called: false,
|
||||||
|
main_context,
|
||||||
|
});
|
||||||
|
|
||||||
|
scope.set_host_create_shadow_realm_context_callback(|scope| {
|
||||||
|
let main_context = {
|
||||||
|
let data = scope.get_slot_mut::<CheckData>().unwrap();
|
||||||
|
data.callback_called = true;
|
||||||
|
data.main_context.clone()
|
||||||
|
};
|
||||||
|
assert_eq!(scope.get_current_context(), main_context);
|
||||||
|
|
||||||
|
// Can't return None without throwing.
|
||||||
|
let message = v8::String::new(scope, "Unsupported").unwrap();
|
||||||
|
let exception = v8::Exception::type_error(scope, message);
|
||||||
|
scope.throw_exception(exception);
|
||||||
|
None
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
let tc_scope = &mut v8::TryCatch::new(scope);
|
||||||
|
assert!(eval(tc_scope, "new ShadowRealm()").is_none());
|
||||||
|
assert!(tc_scope.has_caught());
|
||||||
|
assert!(tc_scope.get_slot::<CheckData>().unwrap().callback_called);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.set_host_create_shadow_realm_context_callback(|scope| {
|
||||||
|
let main_context = {
|
||||||
|
let data = scope.get_slot_mut::<CheckData>().unwrap();
|
||||||
|
data.callback_called = true;
|
||||||
|
data.main_context.clone()
|
||||||
|
};
|
||||||
|
assert_eq!(scope.get_current_context(), main_context);
|
||||||
|
|
||||||
|
let new_context = v8::Context::new(scope);
|
||||||
|
{
|
||||||
|
let scope = &mut v8::ContextScope::new(scope, new_context);
|
||||||
|
let global = new_context.global(scope);
|
||||||
|
let key = v8::String::new(scope, "test").unwrap();
|
||||||
|
let value = v8::Integer::new(scope, 42);
|
||||||
|
global.set(scope, key.into(), value.into()).unwrap();
|
||||||
|
}
|
||||||
|
Some(new_context)
|
||||||
|
});
|
||||||
|
|
||||||
|
let value =
|
||||||
|
eval(scope, "new ShadowRealm().evaluate(`globalThis.test`)").unwrap();
|
||||||
|
assert_eq!(value.uint32_value(scope), Some(42));
|
||||||
|
assert!(scope.get_slot::<CheckData>().unwrap().callback_called);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue