mirror of
https://github.com/denoland/rusty_v8.git
synced 2025-01-22 06:09:47 -05: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 "support.h"
|
||||
#include "v8-callbacks.h"
|
||||
#include "v8/include/libplatform/libplatform.h"
|
||||
#include "v8/include/v8-fast-api-calls.h"
|
||||
#include "v8/include/v8-inspector.h"
|
||||
|
@ -263,6 +264,11 @@ void v8__Isolate__SetHostImportModuleDynamicallyCallback(
|
|||
HostImportModuleDynamicallyCallback);
|
||||
}
|
||||
|
||||
void v8__Isolate__SetHostCreateShadowRealmContextCallback(
|
||||
v8::Isolate* isolate, v8::HostCreateShadowRealmContextCallback callback) {
|
||||
isolate->SetHostCreateShadowRealmContextCallback(callback);
|
||||
}
|
||||
|
||||
bool v8__Isolate__AddMessageListener(v8::Isolate* isolate,
|
||||
v8::MessageCallback callback) {
|
||||
return isolate->AddMessageListener(callback);
|
||||
|
|
|
@ -129,6 +129,19 @@ pub type HostImportModuleDynamicallyCallback = extern "C" fn(
|
|||
Local<FixedArray>,
|
||||
) -> *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 =
|
||||
extern "C" fn(isolate: &mut Isolate, data: *mut c_void);
|
||||
|
||||
|
@ -222,6 +235,19 @@ extern "C" {
|
|||
isolate: *mut Isolate,
|
||||
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(
|
||||
isolate: *const Isolate,
|
||||
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.
|
||||
/// If multiple callbacks are added, only the most recently added callback is
|
||||
/// invoked.
|
||||
|
|
|
@ -92,6 +92,7 @@ pub use handle::Handle;
|
|||
pub use handle::Local;
|
||||
pub use handle::Weak;
|
||||
pub use isolate::HeapStatistics;
|
||||
pub use isolate::HostCreateShadowRealmContextCallback;
|
||||
pub use isolate::HostImportModuleDynamicallyCallback;
|
||||
pub use isolate::HostInitializeImportMetaObjectCallback;
|
||||
pub use isolate::Isolate;
|
||||
|
|
|
@ -35,7 +35,9 @@ fn setup() -> SetupGuard {
|
|||
"../third_party/icu/common/icudtl.dat"
|
||||
))
|
||||
.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::new_default_platform(0, false).make_shared(),
|
||||
);
|
||||
|
@ -6728,3 +6730,76 @@ fn finalizer_on_kept_global() {
|
|||
drop(weak);
|
||||
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