mirror of
https://github.com/denoland/rusty_v8.git
synced 2025-02-15 01:55:56 -05:00
feat: dynamic import phase callback
This commit is contained in:
parent
7d1ebb20a7
commit
69bc7be3c8
6 changed files with 256 additions and 0 deletions
1
build.rs
1
build.rs
|
@ -154,6 +154,7 @@ fn build_binding() {
|
||||||
.clang_args(args)
|
.clang_args(args)
|
||||||
.generate_cstr(true)
|
.generate_cstr(true)
|
||||||
.rustified_enum(".*UseCounterFeature")
|
.rustified_enum(".*UseCounterFeature")
|
||||||
|
.rustified_enum(".*ModuleImportPhase")
|
||||||
.allowlist_item("v8__.*")
|
.allowlist_item("v8__.*")
|
||||||
.allowlist_item("cppgc__.*")
|
.allowlist_item("cppgc__.*")
|
||||||
.allowlist_item("RustObj")
|
.allowlist_item("RustObj")
|
||||||
|
|
|
@ -272,6 +272,12 @@ void v8__Isolate__SetHostImportModuleDynamicallyCallback(
|
||||||
isolate->SetHostImportModuleDynamicallyCallback(callback);
|
isolate->SetHostImportModuleDynamicallyCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void v8__Isolate__SetHostImportModuleWithPhaseDynamicallyCallback(
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
v8::HostImportModuleWithPhaseDynamicallyCallback callback) {
|
||||||
|
isolate->SetHostImportModuleWithPhaseDynamicallyCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
void v8__Isolate__SetHostCreateShadowRealmContextCallback(
|
void v8__Isolate__SetHostCreateShadowRealmContextCallback(
|
||||||
v8::Isolate* isolate, v8::HostCreateShadowRealmContextCallback callback) {
|
v8::Isolate* isolate, v8::HostCreateShadowRealmContextCallback callback) {
|
||||||
isolate->SetHostCreateShadowRealmContextCallback(callback);
|
isolate->SetHostCreateShadowRealmContextCallback(callback);
|
||||||
|
|
|
@ -39,6 +39,7 @@ using v8__CFunctionInfo = v8::CFunctionInfo;
|
||||||
using v8__FastOneByteString = v8::FastOneByteString;
|
using v8__FastOneByteString = v8::FastOneByteString;
|
||||||
using v8__Isolate__UseCounterFeature = v8::Isolate::UseCounterFeature;
|
using v8__Isolate__UseCounterFeature = v8::Isolate::UseCounterFeature;
|
||||||
using v8__String__WriteFlags = v8::String::WriteFlags;
|
using v8__String__WriteFlags = v8::String::WriteFlags;
|
||||||
|
using v8__ModuleImportPhase = v8::ModuleImportPhase;
|
||||||
|
|
||||||
static uint32_t v8__MAJOR_VERSION = V8_MAJOR_VERSION;
|
static uint32_t v8__MAJOR_VERSION = V8_MAJOR_VERSION;
|
||||||
static uint32_t v8__MINOR_VERSION = V8_MINOR_VERSION;
|
static uint32_t v8__MINOR_VERSION = V8_MINOR_VERSION;
|
||||||
|
|
190
src/isolate.rs
190
src/isolate.rs
|
@ -1,5 +1,6 @@
|
||||||
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
||||||
use crate::binding::v8__Isolate__UseCounterFeature;
|
use crate::binding::v8__Isolate__UseCounterFeature;
|
||||||
|
pub use crate::binding::v8__ModuleImportPhase as ModuleImportPhase;
|
||||||
use crate::cppgc::Heap;
|
use crate::cppgc::Heap;
|
||||||
use crate::function::FunctionCallbackInfo;
|
use crate::function::FunctionCallbackInfo;
|
||||||
use crate::gc::GCCallbackFlags;
|
use crate::gc::GCCallbackFlags;
|
||||||
|
@ -340,6 +341,171 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// HostImportModuleWithPhaseDynamicallyCallback is called when we
|
||||||
|
/// require the embedder to load a module with a specific phase. This is used
|
||||||
|
/// as part of the dynamic import syntax.
|
||||||
|
///
|
||||||
|
/// The referrer contains metadata about the script/module that calls
|
||||||
|
/// import.
|
||||||
|
///
|
||||||
|
/// The specifier is the name of the module that should be imported.
|
||||||
|
///
|
||||||
|
/// The phase is the phase of the import requested.
|
||||||
|
///
|
||||||
|
/// The import_attributes are import attributes for this request in the form:
|
||||||
|
/// [key1, value1, key2, value2, ...] where the keys and values are of type
|
||||||
|
/// v8::String. Note, unlike the FixedArray passed to ResolveModuleCallback and
|
||||||
|
/// returned from ModuleRequest::GetImportAttributes(), this array does not
|
||||||
|
/// contain the source Locations of the attributes.
|
||||||
|
///
|
||||||
|
/// The Promise returned from this function is forwarded to userland
|
||||||
|
/// JavaScript. The embedder must resolve this promise according to the phase
|
||||||
|
/// requested:
|
||||||
|
/// - For ModuleImportPhase::kSource, the promise must be resolved with a
|
||||||
|
/// compiled ModuleSource object, or rejected with a SyntaxError if the
|
||||||
|
/// module does not support source representation.
|
||||||
|
/// - For ModuleImportPhase::kEvaluation, the promise must be resolved with a
|
||||||
|
/// ModuleNamespace object of a module that has been compiled, instantiated,
|
||||||
|
/// and evaluated.
|
||||||
|
///
|
||||||
|
/// In case of an exception, the embedder must reject this promise with the
|
||||||
|
/// exception. If the promise creation itself fails (e.g. due to stack
|
||||||
|
/// overflow), the embedder must propagate that exception by returning an empty
|
||||||
|
/// MaybeLocal.
|
||||||
|
///
|
||||||
|
/// This callback is still experimental and is only invoked for source phase
|
||||||
|
/// imports.
|
||||||
|
pub trait HostImportModuleWithPhaseDynamicallyCallback:
|
||||||
|
UnitType
|
||||||
|
+ for<'s> FnOnce(
|
||||||
|
&mut HandleScope<'s>,
|
||||||
|
Local<'s, Data>,
|
||||||
|
Local<'s, Value>,
|
||||||
|
Local<'s, String>,
|
||||||
|
ModuleImportPhase,
|
||||||
|
Local<'s, FixedArray>,
|
||||||
|
) -> Option<Local<'s, Promise>>
|
||||||
|
{
|
||||||
|
fn to_c_fn(self) -> RawHostImportModuleWithPhaseDynamicallyCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
pub(crate) type RawHostImportModuleWithPhaseDynamicallyCallback =
|
||||||
|
for<'s> extern "C" fn(
|
||||||
|
Local<'s, Context>,
|
||||||
|
Local<'s, Data>,
|
||||||
|
Local<'s, Value>,
|
||||||
|
Local<'s, String>,
|
||||||
|
ModuleImportPhase,
|
||||||
|
Local<'s, FixedArray>,
|
||||||
|
) -> *mut Promise;
|
||||||
|
|
||||||
|
#[cfg(all(target_family = "windows", target_arch = "x86_64"))]
|
||||||
|
pub type RawHostImportModuleWithPhaseDynamicallyCallback =
|
||||||
|
for<'s> extern "C" fn(
|
||||||
|
*mut *mut Promise,
|
||||||
|
Local<'s, Context>,
|
||||||
|
Local<'s, Data>,
|
||||||
|
Local<'s, Value>,
|
||||||
|
Local<'s, String>,
|
||||||
|
ModuleImportPhase,
|
||||||
|
Local<'s, FixedArray>,
|
||||||
|
) -> *mut *mut Promise;
|
||||||
|
|
||||||
|
impl<F> HostImportModuleWithPhaseDynamicallyCallback for F
|
||||||
|
where
|
||||||
|
F: UnitType
|
||||||
|
+ for<'s> FnOnce(
|
||||||
|
&mut HandleScope<'s>,
|
||||||
|
Local<'s, Data>,
|
||||||
|
Local<'s, Value>,
|
||||||
|
Local<'s, String>,
|
||||||
|
ModuleImportPhase,
|
||||||
|
Local<'s, FixedArray>,
|
||||||
|
) -> Option<Local<'s, Promise>>,
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn to_c_fn(self) -> RawHostImportModuleWithPhaseDynamicallyCallback {
|
||||||
|
#[inline(always)]
|
||||||
|
fn scope_adapter<'s, F: HostImportModuleWithPhaseDynamicallyCallback>(
|
||||||
|
context: Local<'s, Context>,
|
||||||
|
host_defined_options: Local<'s, Data>,
|
||||||
|
resource_name: Local<'s, Value>,
|
||||||
|
specifier: Local<'s, String>,
|
||||||
|
import_phase: ModuleImportPhase,
|
||||||
|
import_attributes: Local<'s, FixedArray>,
|
||||||
|
) -> Option<Local<'s, Promise>> {
|
||||||
|
let scope = &mut unsafe { CallbackScope::new(context) };
|
||||||
|
(F::get())(
|
||||||
|
scope,
|
||||||
|
host_defined_options,
|
||||||
|
resource_name,
|
||||||
|
specifier,
|
||||||
|
import_phase,
|
||||||
|
import_attributes,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
#[inline(always)]
|
||||||
|
extern "C" fn abi_adapter<
|
||||||
|
's,
|
||||||
|
F: HostImportModuleWithPhaseDynamicallyCallback,
|
||||||
|
>(
|
||||||
|
context: Local<'s, Context>,
|
||||||
|
host_defined_options: Local<'s, Data>,
|
||||||
|
resource_name: Local<'s, Value>,
|
||||||
|
specifier: Local<'s, String>,
|
||||||
|
import_phase: ModuleImportPhase,
|
||||||
|
import_attributes: Local<'s, FixedArray>,
|
||||||
|
) -> *mut Promise {
|
||||||
|
scope_adapter::<F>(
|
||||||
|
context,
|
||||||
|
host_defined_options,
|
||||||
|
resource_name,
|
||||||
|
specifier,
|
||||||
|
import_phase,
|
||||||
|
import_attributes,
|
||||||
|
)
|
||||||
|
.map_or_else(null_mut, |return_value| return_value.as_non_null().as_ptr())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(target_family = "windows", target_arch = "x86_64"))]
|
||||||
|
#[inline(always)]
|
||||||
|
extern "C" fn abi_adapter<
|
||||||
|
's,
|
||||||
|
F: HostImportModuleWithPhaseDynamicallyCallback,
|
||||||
|
>(
|
||||||
|
return_value: *mut *mut Promise,
|
||||||
|
context: Local<'s, Context>,
|
||||||
|
host_defined_options: Local<'s, Data>,
|
||||||
|
resource_name: Local<'s, Value>,
|
||||||
|
specifier: Local<'s, String>,
|
||||||
|
import_phase: ModuleImportPhase,
|
||||||
|
import_attributes: Local<'s, FixedArray>,
|
||||||
|
) -> *mut *mut Promise {
|
||||||
|
unsafe {
|
||||||
|
std::ptr::write(
|
||||||
|
return_value,
|
||||||
|
scope_adapter::<F>(
|
||||||
|
context,
|
||||||
|
host_defined_options,
|
||||||
|
resource_name,
|
||||||
|
specifier,
|
||||||
|
import_phase,
|
||||||
|
import_attributes,
|
||||||
|
)
|
||||||
|
.map(|return_value| return_value.as_non_null().as_ptr())
|
||||||
|
.unwrap_or_else(null_mut),
|
||||||
|
);
|
||||||
|
return_value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abi_adapter::<F>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// `HostCreateShadowRealmContextCallback` is called each time a `ShadowRealm`
|
/// `HostCreateShadowRealmContextCallback` is called each time a `ShadowRealm`
|
||||||
/// is being constructed. You can use [`HandleScope::get_current_context`] to
|
/// is being constructed. You can use [`HandleScope::get_current_context`] to
|
||||||
/// get the [`Context`] in which the constructor is being run.
|
/// get the [`Context`] in which the constructor is being run.
|
||||||
|
@ -497,6 +663,10 @@ extern "C" {
|
||||||
isolate: *mut Isolate,
|
isolate: *mut Isolate,
|
||||||
callback: RawHostImportModuleDynamicallyCallback,
|
callback: RawHostImportModuleDynamicallyCallback,
|
||||||
);
|
);
|
||||||
|
fn v8__Isolate__SetHostImportModuleWithPhaseDynamicallyCallback(
|
||||||
|
isolate: *mut Isolate,
|
||||||
|
callback: RawHostImportModuleWithPhaseDynamicallyCallback,
|
||||||
|
);
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
fn v8__Isolate__SetHostCreateShadowRealmContextCallback(
|
fn v8__Isolate__SetHostCreateShadowRealmContextCallback(
|
||||||
isolate: *mut Isolate,
|
isolate: *mut Isolate,
|
||||||
|
@ -1088,6 +1258,26 @@ impl Isolate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This specifies the callback called by the upcoming dynamic
|
||||||
|
/// import() and import.source() language feature to load modules.
|
||||||
|
///
|
||||||
|
/// This API is experimental and is expected to be changed or removed in the
|
||||||
|
/// future. The callback is currently only called when for source-phase
|
||||||
|
/// imports. Evaluation-phase imports use the existing
|
||||||
|
/// HostImportModuleDynamicallyCallback callback.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn set_host_import_module_with_phase_dynamically_callback(
|
||||||
|
&mut self,
|
||||||
|
callback: impl HostImportModuleWithPhaseDynamicallyCallback,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
v8__Isolate__SetHostImportModuleWithPhaseDynamicallyCallback(
|
||||||
|
self,
|
||||||
|
callback.to_c_fn(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This specifies the callback called by the upcoming `ShadowRealm`
|
/// This specifies the callback called by the upcoming `ShadowRealm`
|
||||||
/// construction language feature to retrieve host created globals.
|
/// construction language feature to retrieve host created globals.
|
||||||
pub fn set_host_create_shadow_realm_context_callback(
|
pub fn set_host_create_shadow_realm_context_callback(
|
||||||
|
|
|
@ -107,6 +107,7 @@ pub use isolate::GarbageCollectionType;
|
||||||
pub use isolate::HeapStatistics;
|
pub use isolate::HeapStatistics;
|
||||||
pub use isolate::HostCreateShadowRealmContextCallback;
|
pub use isolate::HostCreateShadowRealmContextCallback;
|
||||||
pub use isolate::HostImportModuleDynamicallyCallback;
|
pub use isolate::HostImportModuleDynamicallyCallback;
|
||||||
|
pub use isolate::HostImportModuleWithPhaseDynamicallyCallback;
|
||||||
pub use isolate::HostInitializeImportMetaObjectCallback;
|
pub use isolate::HostInitializeImportMetaObjectCallback;
|
||||||
pub use isolate::Isolate;
|
pub use isolate::Isolate;
|
||||||
pub use isolate::IsolateHandle;
|
pub use isolate::IsolateHandle;
|
||||||
|
@ -114,6 +115,7 @@ pub use isolate::MemoryPressureLevel;
|
||||||
pub use isolate::MessageCallback;
|
pub use isolate::MessageCallback;
|
||||||
pub use isolate::MessageErrorLevel;
|
pub use isolate::MessageErrorLevel;
|
||||||
pub use isolate::MicrotasksPolicy;
|
pub use isolate::MicrotasksPolicy;
|
||||||
|
pub use isolate::ModuleImportPhase;
|
||||||
pub use isolate::NearHeapLimitCallback;
|
pub use isolate::NearHeapLimitCallback;
|
||||||
pub use isolate::OomDetails;
|
pub use isolate::OomDetails;
|
||||||
pub use isolate::OomErrorCallback;
|
pub use isolate::OomErrorCallback;
|
||||||
|
|
|
@ -7801,6 +7801,62 @@ fn static_source_phase_import() {
|
||||||
assert_eq!(obj, ns.get(scope, default.into()).unwrap());
|
assert_eq!(obj, ns.get(scope, default.into()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dynamic_source_phase_import() {
|
||||||
|
let _setup_guard = setup::parallel_test();
|
||||||
|
let isolate = &mut v8::Isolate::new(Default::default());
|
||||||
|
|
||||||
|
let scope = &mut v8::HandleScope::new(isolate);
|
||||||
|
|
||||||
|
let context = v8::Context::new(scope, Default::default());
|
||||||
|
let scope = &mut v8::ContextScope::new(scope, context);
|
||||||
|
|
||||||
|
let obj = eval(scope, "new WebAssembly.Module(new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]))").unwrap().cast::<v8::Object>();
|
||||||
|
|
||||||
|
context.set_slot(v8::Global::new(scope, obj));
|
||||||
|
|
||||||
|
fn dynamic_import_cb<'s>(
|
||||||
|
_scope: &mut v8::HandleScope<'s>,
|
||||||
|
_host_defined_options: v8::Local<'s, v8::Data>,
|
||||||
|
_resource_name: v8::Local<'s, v8::Value>,
|
||||||
|
_specifier: v8::Local<'s, v8::String>,
|
||||||
|
_import_attributes: v8::Local<'s, v8::FixedArray>,
|
||||||
|
) -> Option<v8::Local<'s, v8::Promise>> {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dynamic_import_phase_cb<'s>(
|
||||||
|
scope: &mut v8::HandleScope<'s>,
|
||||||
|
_host_defined_options: v8::Local<'s, v8::Data>,
|
||||||
|
_resource_name: v8::Local<'s, v8::Value>,
|
||||||
|
_specifier: v8::Local<'s, v8::String>,
|
||||||
|
phase: v8::ModuleImportPhase,
|
||||||
|
_import_attributes: v8::Local<'s, v8::FixedArray>,
|
||||||
|
) -> Option<v8::Local<'s, v8::Promise>> {
|
||||||
|
assert_eq!(phase, v8::ModuleImportPhase::kSource);
|
||||||
|
|
||||||
|
let resolver = v8::PromiseResolver::new(scope).unwrap();
|
||||||
|
|
||||||
|
let context = scope.get_current_context();
|
||||||
|
let global = context.get_slot::<v8::Global<v8::Object>>().unwrap();
|
||||||
|
let obj = v8::Local::new(scope, global);
|
||||||
|
resolver.resolve(scope, obj.into());
|
||||||
|
|
||||||
|
Some(resolver.get_promise(scope))
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.set_host_import_module_dynamically_callback(dynamic_import_cb);
|
||||||
|
scope.set_host_import_module_with_phase_dynamically_callback(
|
||||||
|
dynamic_import_phase_cb,
|
||||||
|
);
|
||||||
|
|
||||||
|
let promise = eval(scope, "import.source('a')")
|
||||||
|
.unwrap()
|
||||||
|
.cast::<v8::Promise>();
|
||||||
|
eprintln!("{}", promise.result(scope).to_rust_string_lossy(scope));
|
||||||
|
assert_eq!(obj, promise.result(scope));
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::float_cmp)]
|
#[allow(clippy::float_cmp)]
|
||||||
#[test]
|
#[test]
|
||||||
fn date() {
|
fn date() {
|
||||||
|
|
Loading…
Add table
Reference in a new issue