Skip to content

Commit 4a56d2d

Browse files
bartlomiejudevsnek
andauthored
feat: Add support for source phase imports (#1701)
* feat: Add support for source phase imports * fmt * fix windows * undo * test --------- Co-authored-by: snek <snek@deno.com>
1 parent 7b0ee75 commit 4a56d2d

File tree

3 files changed

+138
-6
lines changed

3 files changed

+138
-6
lines changed

src/binding.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3252,11 +3252,12 @@ int v8__Module__ScriptId(const v8::Module& self) {
32523252
return const_cast<v8::Module&>(self).ScriptId();
32533253
}
32543254

3255-
MaybeBool v8__Module__InstantiateModule(const v8::Module& self,
3256-
const v8::Context& context,
3257-
v8::Module::ResolveModuleCallback cb) {
3258-
return maybe_to_maybe_bool(
3259-
ptr_to_local(&self)->InstantiateModule(ptr_to_local(&context), cb));
3255+
MaybeBool v8__Module__InstantiateModule(
3256+
const v8::Module& self, const v8::Context& context,
3257+
v8::Module::ResolveModuleCallback cb,
3258+
v8::Module::ResolveSourceCallback source_callback) {
3259+
return maybe_to_maybe_bool(ptr_to_local(&self)->InstantiateModule(
3260+
ptr_to_local(&context), cb, source_callback));
32603261
}
32613262

32623263
const v8::Value* v8__Module__Evaluate(const v8::Module& self,

src/module.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::Local;
1616
use crate::Message;
1717
use crate::Module;
1818
use crate::ModuleRequest;
19+
use crate::Object;
1920
use crate::String;
2021
use crate::UnboundModuleScript;
2122
use crate::Value;
@@ -146,6 +147,64 @@ where
146147
}
147148
}
148149

150+
// System V ABI
151+
#[cfg(not(target_os = "windows"))]
152+
#[repr(C)]
153+
pub struct ResolveSourceCallbackRet(*const Object);
154+
155+
#[cfg(not(target_os = "windows"))]
156+
pub type ResolveSourceCallback<'a> = extern "C" fn(
157+
Local<'a, Context>,
158+
Local<'a, String>,
159+
Local<'a, FixedArray>,
160+
Local<'a, Module>,
161+
) -> ResolveSourceCallbackRet;
162+
163+
// Windows x64 ABI: Local<Module> returned on the stack.
164+
#[cfg(target_os = "windows")]
165+
pub type ResolveSourceCallback<'a> = extern "C" fn(
166+
*mut *const Object,
167+
Local<'a, Context>,
168+
Local<'a, String>,
169+
Local<'a, FixedArray>,
170+
Local<'a, Module>,
171+
) -> *mut *const Object;
172+
173+
impl<'a, F> MapFnFrom<F> for ResolveSourceCallback<'a>
174+
where
175+
F: UnitType
176+
+ Fn(
177+
Local<'a, Context>,
178+
Local<'a, String>,
179+
Local<'a, FixedArray>,
180+
Local<'a, Module>,
181+
) -> Option<Local<'a, Object>>,
182+
{
183+
#[cfg(not(target_os = "windows"))]
184+
fn mapping() -> Self {
185+
let f = |context, specifier, import_attributes, referrer| {
186+
ResolveSourceCallbackRet(
187+
(F::get())(context, specifier, import_attributes, referrer)
188+
.map(|r| -> *const Object { &*r })
189+
.unwrap_or(null()),
190+
)
191+
};
192+
f.to_c_fn()
193+
}
194+
195+
#[cfg(target_os = "windows")]
196+
fn mapping() -> Self {
197+
let f = |ret_ptr, context, specifier, import_attributes, referrer| {
198+
let r = (F::get())(context, specifier, import_attributes, referrer)
199+
.map(|r| -> *const Object { &*r })
200+
.unwrap_or(null());
201+
unsafe { std::ptr::write(ret_ptr, r) }; // Write result to stack.
202+
ret_ptr // Return stack pointer to the return value.
203+
};
204+
f.to_c_fn()
205+
}
206+
}
207+
149208
extern "C" {
150209
fn v8__Module__GetStatus(this: *const Module) -> ModuleStatus;
151210
fn v8__Module__GetException(this: *const Module) -> *const Value;
@@ -162,6 +221,7 @@ extern "C" {
162221
this: *const Module,
163222
context: *const Context,
164223
cb: ResolveModuleCallback,
224+
source_callback: Option<ResolveSourceCallback>,
165225
) -> MaybeBool;
166226
fn v8__Module__Evaluate(
167227
this: *const Module,
@@ -323,6 +383,31 @@ impl Module {
323383
self,
324384
&*scope.get_current_context(),
325385
callback.map_fn_to(),
386+
None,
387+
)
388+
}
389+
.into()
390+
}
391+
392+
/// Instantiates the module and its dependencies.
393+
///
394+
/// Returns an empty Maybe<bool> if an exception occurred during
395+
/// instantiation. (In the case where the callback throws an exception, that
396+
/// exception is propagated.)
397+
#[must_use]
398+
#[inline(always)]
399+
pub fn instantiate_module2<'a>(
400+
&self,
401+
scope: &mut HandleScope,
402+
callback: impl MapFnTo<ResolveModuleCallback<'a>>,
403+
source_callback: impl MapFnTo<ResolveSourceCallback<'a>>,
404+
) -> Option<bool> {
405+
unsafe {
406+
v8__Module__InstantiateModule(
407+
self,
408+
&*scope.get_current_context(),
409+
callback.map_fn_to(),
410+
Some(source_callback.map_fn_to()),
326411
)
327412
}
328413
.into()

tests/test_api.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ mod setup {
5151
))
5252
.is_ok());
5353
v8::V8::set_flags_from_string(
54-
"--no_freeze_flags_after_init --expose_gc --harmony-shadow-realm --allow_natives_syntax --turbo_fast_api_calls",
54+
"--no_freeze_flags_after_init --expose_gc --harmony-shadow-realm --allow_natives_syntax --turbo_fast_api_calls --js-source-phase-imports",
5555
);
5656
v8::V8::initialize_platform(
5757
v8::new_unprotected_default_platform(0, false).make_shared(),
@@ -7755,6 +7755,52 @@ fn synthetic_module() {
77557755
check("b", 2.0);
77567756
}
77577757

7758+
#[test]
7759+
fn static_source_phase_import() {
7760+
let _setup_guard = setup::parallel_test();
7761+
let isolate = &mut v8::Isolate::new(Default::default());
7762+
7763+
let scope = &mut v8::HandleScope::new(isolate);
7764+
7765+
let context = v8::Context::new(scope, Default::default());
7766+
let scope = &mut v8::ContextScope::new(scope, context);
7767+
7768+
let module = create_module(
7769+
scope,
7770+
"import source mod from 'z'; export default mod;",
7771+
None,
7772+
v8::script_compiler::CompileOptions::NoCompileOptions,
7773+
);
7774+
7775+
let obj = eval(scope, "new WebAssembly.Module(new Uint8Array([0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]))").unwrap().cast::<v8::Object>();
7776+
7777+
context.set_slot(v8::Global::new(scope, obj));
7778+
7779+
fn resolve_source<'a>(
7780+
context: v8::Local<'a, v8::Context>,
7781+
_specifier: v8::Local<'a, v8::String>,
7782+
_import_attributes: v8::Local<'a, v8::FixedArray>,
7783+
_referrer: v8::Local<'a, v8::Module>,
7784+
) -> Option<v8::Local<'a, v8::Object>> {
7785+
let scope = unsafe { &mut v8::CallbackScope::new(context) };
7786+
let global = context.get_slot::<v8::Global<v8::Object>>().unwrap();
7787+
Some(v8::Local::new(scope, global))
7788+
}
7789+
7790+
module
7791+
.instantiate_module2(
7792+
scope,
7793+
unexpected_module_resolve_callback,
7794+
resolve_source,
7795+
)
7796+
.unwrap();
7797+
module.evaluate(scope).unwrap();
7798+
7799+
let ns = module.get_module_namespace().cast::<v8::Object>();
7800+
let default = v8::String::new(scope, "default").unwrap();
7801+
assert_eq!(obj, ns.get(scope, default.into()).unwrap());
7802+
}
7803+
77587804
#[allow(clippy::float_cmp)]
77597805
#[test]
77607806
fn date() {

0 commit comments

Comments
 (0)