mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-26 00:59:28 -05:00
Support dynamic import (#136)
This commit is contained in:
parent
0303984286
commit
ce38f674f7
4 changed files with 160 additions and 27 deletions
|
@ -8,6 +8,8 @@
|
||||||
#include "v8/include/v8-platform.h"
|
#include "v8/include/v8-platform.h"
|
||||||
#include "v8/include/v8.h"
|
#include "v8/include/v8.h"
|
||||||
|
|
||||||
|
const uint32_t kSlotDynamicImport = 1000;
|
||||||
|
|
||||||
using namespace support;
|
using namespace support;
|
||||||
|
|
||||||
static_assert(sizeof(v8::ScriptOrigin) == sizeof(size_t) * 7,
|
static_assert(sizeof(v8::ScriptOrigin) == sizeof(size_t) * 7,
|
||||||
|
@ -39,6 +41,27 @@ static_assert(sizeof(v8::Location) == sizeof(size_t) * 1,
|
||||||
static_assert(sizeof(v8::SnapshotCreator) == sizeof(size_t) * 1,
|
static_assert(sizeof(v8::SnapshotCreator) == sizeof(size_t) * 1,
|
||||||
"SnapshotCreator size mismatch");
|
"SnapshotCreator size mismatch");
|
||||||
|
|
||||||
|
// This is an extern C calling convention compatible version of
|
||||||
|
// v8::HostImportModuleDynamicallyCallback
|
||||||
|
typedef v8::Promise* (*v8__HostImportModuleDynamicallyCallback)(
|
||||||
|
v8::Local<v8::Context> context, v8::Local<v8::ScriptOrModule> referrer,
|
||||||
|
v8::Local<v8::String> specifier);
|
||||||
|
|
||||||
|
v8::MaybeLocal<v8::Promise> HostImportModuleDynamicallyCallback(
|
||||||
|
v8::Local<v8::Context> context, v8::Local<v8::ScriptOrModule> referrer,
|
||||||
|
v8::Local<v8::String> specifier) {
|
||||||
|
auto* isolate = context->GetIsolate();
|
||||||
|
auto* callback = reinterpret_cast<v8__HostImportModuleDynamicallyCallback>(
|
||||||
|
isolate->GetData(kSlotDynamicImport));
|
||||||
|
assert(callback != nullptr);
|
||||||
|
auto* promise_ptr = callback(context, referrer, specifier);
|
||||||
|
if (promise_ptr == nullptr) {
|
||||||
|
return v8::MaybeLocal<v8::Promise>();
|
||||||
|
} else {
|
||||||
|
return v8::MaybeLocal<v8::Promise>(ptr_to_local(promise_ptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
void v8__V8__SetFlagsFromCommandLine(int* argc, char** argv) {
|
void v8__V8__SetFlagsFromCommandLine(int* argc, char** argv) {
|
||||||
|
@ -102,6 +125,13 @@ void v8__Isolate__SetHostInitializeImportMetaObjectCallback(
|
||||||
isolate->SetHostInitializeImportMetaObjectCallback(callback);
|
isolate->SetHostInitializeImportMetaObjectCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void v8__Isolate__SetHostImportModuleDynamicallyCallback(
|
||||||
|
v8::Isolate* isolate, v8__HostImportModuleDynamicallyCallback callback) {
|
||||||
|
isolate->SetData(kSlotDynamicImport, reinterpret_cast<void*>(callback));
|
||||||
|
isolate->SetHostImportModuleDynamicallyCallback(
|
||||||
|
HostImportModuleDynamicallyCallback);
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
@ -546,8 +576,10 @@ void v8__TryCatch__SetCaptureMessage(v8::TryCatch& self, bool value) {
|
||||||
self.SetCaptureMessage(value);
|
self.SetCaptureMessage(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Uint8Array* v8__Uint8Array__New(v8::ArrayBuffer* buf_ptr, size_t byte_offset, size_t length) {
|
v8::Uint8Array* v8__Uint8Array__New(v8::ArrayBuffer* buf_ptr,
|
||||||
return local_to_ptr(v8::Uint8Array::New(ptr_to_local(buf_ptr), byte_offset, length));
|
size_t byte_offset, size_t length) {
|
||||||
|
return local_to_ptr(
|
||||||
|
v8::Uint8Array::New(ptr_to_local(buf_ptr), byte_offset, length));
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Script* v8__Script__Compile(v8::Context* context, v8::String* source,
|
v8::Script* v8__Script__Compile(v8::Context* context, v8::String* source,
|
||||||
|
|
|
@ -9,20 +9,55 @@ use crate::Local;
|
||||||
use crate::Message;
|
use crate::Message;
|
||||||
use crate::Module;
|
use crate::Module;
|
||||||
use crate::Object;
|
use crate::Object;
|
||||||
|
use crate::Promise;
|
||||||
|
use crate::ScriptOrModule;
|
||||||
use crate::StartupData;
|
use crate::StartupData;
|
||||||
|
use crate::String;
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
type MessageCallback = extern "C" fn(Local<Message>, Local<Value>);
|
pub type MessageCallback = extern "C" fn(Local<Message>, Local<Value>);
|
||||||
|
|
||||||
type PromiseRejectCallback = extern "C" fn(PromiseRejectMessage);
|
pub type PromiseRejectCallback = extern "C" fn(PromiseRejectMessage);
|
||||||
|
|
||||||
type HostInitializeImportMetaObjectCallback =
|
/// HostInitializeImportMetaObjectCallback is called the first time import.meta
|
||||||
|
/// is accessed for a module. Subsequent access will reuse the same value.
|
||||||
|
///
|
||||||
|
/// The method combines two implementation-defined abstract operations into one:
|
||||||
|
/// HostGetImportMetaProperties and HostFinalizeImportMeta.
|
||||||
|
///
|
||||||
|
/// The embedder should use v8::Object::CreateDataProperty to add properties on
|
||||||
|
/// the meta object.
|
||||||
|
pub type HostInitializeImportMetaObjectCallback =
|
||||||
extern "C" fn(Local<Context>, Local<Module>, Local<Object>);
|
extern "C" fn(Local<Context>, Local<Module>, Local<Object>);
|
||||||
|
|
||||||
|
/// HostImportModuleDynamicallyCallback is called when we require the
|
||||||
|
/// embedder to load a module. 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 embedder must compile, instantiate, evaluate the Module, and
|
||||||
|
/// obtain it's namespace object.
|
||||||
|
///
|
||||||
|
/// The Promise returned from this function is forwarded to userland
|
||||||
|
/// JavaScript. The embedder must resolve this promise with the module
|
||||||
|
/// namespace object. 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.
|
||||||
|
pub type HostImportModuleDynamicallyCallback = extern "C" fn(
|
||||||
|
Local<Context>,
|
||||||
|
Local<ScriptOrModule>,
|
||||||
|
Local<String>,
|
||||||
|
) -> *mut Promise;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn v8__Isolate__New(params: *mut CreateParams) -> *mut Isolate;
|
fn v8__Isolate__New(params: *mut CreateParams) -> *mut Isolate;
|
||||||
fn v8__Isolate__Dispose(this: *mut Isolate);
|
fn v8__Isolate__Dispose(this: *mut Isolate);
|
||||||
|
@ -48,6 +83,10 @@ extern "C" {
|
||||||
isolate: *mut Isolate,
|
isolate: *mut Isolate,
|
||||||
callback: HostInitializeImportMetaObjectCallback,
|
callback: HostInitializeImportMetaObjectCallback,
|
||||||
);
|
);
|
||||||
|
fn v8__Isolate__SetHostImportModuleDynamicallyCallback(
|
||||||
|
isolate: *mut Isolate,
|
||||||
|
callback: HostImportModuleDynamicallyCallback,
|
||||||
|
);
|
||||||
fn v8__Isolate__ThrowException(
|
fn v8__Isolate__ThrowException(
|
||||||
isolate: &Isolate,
|
isolate: &Isolate,
|
||||||
exception: &Value,
|
exception: &Value,
|
||||||
|
@ -174,6 +213,17 @@ impl Isolate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This specifies the callback called by the upcoming dynamic
|
||||||
|
/// import() language feature to load modules.
|
||||||
|
pub fn set_host_import_module_dynamically_callback(
|
||||||
|
&mut self,
|
||||||
|
callback: HostImportModuleDynamicallyCallback,
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
v8__Isolate__SetHostImportModuleDynamicallyCallback(self, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Schedules an exception to be thrown when returning to JavaScript. When an
|
/// Schedules an exception to be thrown when returning to JavaScript. When an
|
||||||
/// exception has been scheduled it is illegal to invoke any JavaScript
|
/// exception has been scheduled it is illegal to invoke any JavaScript
|
||||||
/// operation; the caller must return immediately and only after the exception
|
/// operation; the caller must return immediately and only after the exception
|
||||||
|
|
|
@ -55,7 +55,7 @@ pub use function::{
|
||||||
};
|
};
|
||||||
pub use global::Global;
|
pub use global::Global;
|
||||||
pub use handle_scope::{EscapableHandleScope, HandleScope, ToLocal};
|
pub use handle_scope::{EscapableHandleScope, HandleScope, ToLocal};
|
||||||
pub use isolate::{InIsolate, Isolate, OwnedIsolate};
|
pub use isolate::*;
|
||||||
pub use local::Local;
|
pub use local::Local;
|
||||||
pub use locker::Locker;
|
pub use locker::Locker;
|
||||||
pub use module::*;
|
pub use module::*;
|
||||||
|
|
|
@ -5,6 +5,7 @@ extern crate lazy_static;
|
||||||
|
|
||||||
use rusty_v8 as v8;
|
use rusty_v8 as v8;
|
||||||
use rusty_v8::{new_null, FunctionCallbackInfo, InIsolate, Local, ToLocal};
|
use rusty_v8::{new_null, FunctionCallbackInfo, InIsolate, Local, ToLocal};
|
||||||
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -339,7 +340,6 @@ fn add_message_listener() {
|
||||||
let mut isolate = v8::Isolate::new(params);
|
let mut isolate = v8::Isolate::new(params);
|
||||||
isolate.set_capture_stack_trace_for_uncaught_exceptions(true, 32);
|
isolate.set_capture_stack_trace_for_uncaught_exceptions(true, 32);
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
||||||
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
extern "C" fn check_message_0(
|
extern "C" fn check_message_0(
|
||||||
|
@ -389,7 +389,6 @@ fn set_host_initialize_import_meta_object_callback() {
|
||||||
params.set_array_buffer_allocator(v8::new_default_allocator());
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
||||||
let mut isolate = v8::Isolate::new(params);
|
let mut isolate = v8::Isolate::new(params);
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
|
||||||
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
extern "C" fn callback(
|
extern "C" fn callback(
|
||||||
|
@ -791,25 +790,6 @@ fn promise_rejected() {
|
||||||
drop(locker);
|
drop(locker);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn fn_callback(info: &FunctionCallbackInfo) {
|
|
||||||
assert_eq!(info.length(), 0);
|
|
||||||
{
|
|
||||||
let rv = &mut info.get_return_value();
|
|
||||||
#[allow(mutable_transmutes)]
|
|
||||||
#[allow(clippy::transmute_ptr_to_ptr)]
|
|
||||||
let info: &mut FunctionCallbackInfo = unsafe { std::mem::transmute(info) };
|
|
||||||
{
|
|
||||||
let mut hs = v8::HandleScope::new(info);
|
|
||||||
let scope = hs.enter();
|
|
||||||
let s = v8::String::new(scope, "Hello callback!").unwrap();
|
|
||||||
let value: Local<v8::Value> = s.into();
|
|
||||||
let rv_value = rv.get(scope);
|
|
||||||
assert!(rv_value.is_undefined());
|
|
||||||
rv.set(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn function() {
|
fn function() {
|
||||||
setup();
|
setup();
|
||||||
|
@ -817,6 +797,27 @@ fn function() {
|
||||||
params.set_array_buffer_allocator(v8::new_default_allocator());
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
||||||
let isolate = v8::Isolate::new(params);
|
let isolate = v8::Isolate::new(params);
|
||||||
let mut locker = v8::Locker::new(&isolate);
|
let mut locker = v8::Locker::new(&isolate);
|
||||||
|
|
||||||
|
extern "C" fn fn_callback(info: &FunctionCallbackInfo) {
|
||||||
|
assert_eq!(info.length(), 0);
|
||||||
|
{
|
||||||
|
let rv = &mut info.get_return_value();
|
||||||
|
#[allow(mutable_transmutes)]
|
||||||
|
#[allow(clippy::transmute_ptr_to_ptr)]
|
||||||
|
let info: &mut FunctionCallbackInfo =
|
||||||
|
unsafe { std::mem::transmute(info) };
|
||||||
|
{
|
||||||
|
let mut hs = v8::HandleScope::new(info);
|
||||||
|
let scope = hs.enter();
|
||||||
|
let s = v8::String::new(scope, "Hello callback!").unwrap();
|
||||||
|
let value: Local<v8::Value> = s.into();
|
||||||
|
let rv_value = rv.get(scope);
|
||||||
|
assert!(rv_value.is_undefined());
|
||||||
|
rv.set(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut hs = v8::HandleScope::new(&mut locker);
|
let mut hs = v8::HandleScope::new(&mut locker);
|
||||||
let scope = hs.enter();
|
let scope = hs.enter();
|
||||||
|
@ -1305,3 +1306,53 @@ fn uint8_array() {
|
||||||
isolate.exit();
|
isolate.exit();
|
||||||
drop(g);
|
drop(g);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dynamic_import() {
|
||||||
|
let g = setup();
|
||||||
|
let mut params = v8::Isolate::create_params();
|
||||||
|
params.set_array_buffer_allocator(v8::new_default_allocator());
|
||||||
|
let mut isolate = v8::Isolate::new(params);
|
||||||
|
|
||||||
|
static CALL_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
|
extern "C" fn dynamic_import_cb(
|
||||||
|
context: v8::Local<v8::Context>,
|
||||||
|
_referrer: v8::Local<v8::ScriptOrModule>,
|
||||||
|
specifier: v8::Local<v8::String>,
|
||||||
|
) -> *mut v8::Promise {
|
||||||
|
let mut cbs = v8::CallbackScope::new(context);
|
||||||
|
let mut hs = v8::HandleScope::new(cbs.enter());
|
||||||
|
let scope = hs.enter();
|
||||||
|
assert!(specifier.strict_equals(v8_str(scope, "bar.js").into()));
|
||||||
|
let e = v8_str(scope, "boom");
|
||||||
|
scope.isolate().throw_exception(e.into());
|
||||||
|
CALL_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
|
std::ptr::null_mut()
|
||||||
|
}
|
||||||
|
isolate.set_host_import_module_dynamically_callback(dynamic_import_cb);
|
||||||
|
|
||||||
|
isolate.enter();
|
||||||
|
let mut locker = v8::Locker::new(&isolate);
|
||||||
|
{
|
||||||
|
let mut hs = v8::HandleScope::new(&mut locker);
|
||||||
|
let s = hs.enter();
|
||||||
|
let mut context = v8::Context::new(s);
|
||||||
|
context.enter();
|
||||||
|
|
||||||
|
let result = eval(
|
||||||
|
s,
|
||||||
|
context,
|
||||||
|
"(async function () {\n\
|
||||||
|
let x = await import('bar.js');\n\
|
||||||
|
})();",
|
||||||
|
);
|
||||||
|
assert!(result.is_some());
|
||||||
|
assert_eq!(CALL_COUNT.load(Ordering::SeqCst), 1);
|
||||||
|
|
||||||
|
context.exit();
|
||||||
|
}
|
||||||
|
drop(locker);
|
||||||
|
isolate.exit();
|
||||||
|
drop(g);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue