mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-26 09:13:46 -05:00
make InstantiateModule work (#124)
This commit is contained in:
parent
7cb6623488
commit
51737506dd
5 changed files with 199 additions and 38 deletions
|
@ -778,10 +778,32 @@ int v8__Module__GetIdentityHash(const v8::Module& self) {
|
||||||
return self.GetIdentityHash();
|
return self.GetIdentityHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is an extern C calling convention compatible version of
|
||||||
|
// v8::Module::ResolveCallback.
|
||||||
|
typedef v8::Module* (*v8__Module__ResolveCallback)(
|
||||||
|
v8::Local<v8::Context> context, v8::Local<v8::String> specifier,
|
||||||
|
v8::Local<v8::Module> referrer);
|
||||||
|
|
||||||
MaybeBool v8__Module__InstantiateModule(v8::Module& self,
|
MaybeBool v8__Module__InstantiateModule(v8::Module& self,
|
||||||
v8::Local<v8::Context> context,
|
v8::Local<v8::Context> context,
|
||||||
v8::Module::ResolveCallback callback) {
|
v8__Module__ResolveCallback c_cb) {
|
||||||
return maybe_to_maybe_bool(self.InstantiateModule(context, callback));
|
static v8__Module__ResolveCallback static_cb = nullptr;
|
||||||
|
assert(static_cb == nullptr);
|
||||||
|
static_cb = c_cb;
|
||||||
|
auto cxx_cb = [](v8::Local<v8::Context> context,
|
||||||
|
v8::Local<v8::String> specifier,
|
||||||
|
v8::Local<v8::Module> referrer) {
|
||||||
|
v8::Module* m = static_cb(context, specifier, referrer);
|
||||||
|
if (m == nullptr) {
|
||||||
|
return v8::MaybeLocal<v8::Module>();
|
||||||
|
} else {
|
||||||
|
return v8::MaybeLocal<v8::Module>(ptr_to_local(m));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto r = maybe_to_maybe_bool(self.InstantiateModule(context, cxx_cb));
|
||||||
|
static_cb = nullptr;
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::Value* v8__Module__Evaluate(v8::Module& self,
|
v8::Value* v8__Module__Evaluate(v8::Module& self,
|
||||||
|
|
|
@ -9,7 +9,7 @@ extern "C" {
|
||||||
fn v8__Context__New(isolate: &Isolate) -> *mut Context;
|
fn v8__Context__New(isolate: &Isolate) -> *mut Context;
|
||||||
fn v8__Context__Enter(this: &mut Context);
|
fn v8__Context__Enter(this: &mut Context);
|
||||||
fn v8__Context__Exit(this: &mut Context);
|
fn v8__Context__Exit(this: &mut Context);
|
||||||
fn v8__Context__GetIsolate(this: &mut Context) -> *mut Isolate;
|
fn v8__Context__GetIsolate<'sc>(this: &'sc Context) -> &'sc mut Isolate;
|
||||||
fn v8__Context__Global(this: *mut Context) -> *mut Object;
|
fn v8__Context__Global(this: *mut Context) -> *mut Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,3 +54,15 @@ impl Context {
|
||||||
unsafe { v8__Context__Exit(self) };
|
unsafe { v8__Context__Exit(self) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsRef<Isolate> for Context {
|
||||||
|
fn as_ref(&self) -> &Isolate {
|
||||||
|
unsafe { v8__Context__GetIsolate(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<Isolate> for Context {
|
||||||
|
fn as_mut(&mut self) -> &mut Isolate {
|
||||||
|
unsafe { v8__Context__GetIsolate(self) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -7,9 +7,16 @@ use crate::String;
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
type ResolveCallback =
|
#[allow(non_camel_case_types)]
|
||||||
|
type v8__Module__ResolveCallback =
|
||||||
extern "C" fn(Local<Context>, Local<String>, Local<Module>) -> *mut Module;
|
extern "C" fn(Local<Context>, Local<String>, Local<Module>) -> *mut Module;
|
||||||
|
|
||||||
|
type ResolveCallback = fn(
|
||||||
|
Local<Context>,
|
||||||
|
Local<String>,
|
||||||
|
Local<Module>,
|
||||||
|
) -> Option<Local<'static, Module>>;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn v8__Module__GetStatus(this: *const Module) -> ModuleStatus;
|
fn v8__Module__GetStatus(this: *const Module) -> ModuleStatus;
|
||||||
fn v8__Module__GetException(this: *const Module) -> *mut Value;
|
fn v8__Module__GetException(this: *const Module) -> *mut Value;
|
||||||
|
@ -25,7 +32,7 @@ extern "C" {
|
||||||
fn v8__Module__InstantiateModule(
|
fn v8__Module__InstantiateModule(
|
||||||
this: *mut Module,
|
this: *mut Module,
|
||||||
context: Local<Context>,
|
context: Local<Context>,
|
||||||
callback: ResolveCallback,
|
callback: v8__Module__ResolveCallback,
|
||||||
) -> MaybeBool;
|
) -> MaybeBool;
|
||||||
fn v8__Module__Evaluate(
|
fn v8__Module__Evaluate(
|
||||||
this: *mut Module,
|
this: *mut Module,
|
||||||
|
@ -117,7 +124,35 @@ impl Module {
|
||||||
context: Local<Context>,
|
context: Local<Context>,
|
||||||
callback: ResolveCallback,
|
callback: ResolveCallback,
|
||||||
) -> Option<bool> {
|
) -> Option<bool> {
|
||||||
unsafe { v8__Module__InstantiateModule(self, context, callback) }.into()
|
use std::sync::Mutex;
|
||||||
|
lazy_static! {
|
||||||
|
static ref RESOLVE_CALLBACK: Mutex<Option<ResolveCallback>> =
|
||||||
|
Mutex::new(None);
|
||||||
|
static ref INSTANTIATE_LOCK: Mutex<()> = Mutex::new(());
|
||||||
|
}
|
||||||
|
let instantiate_guard = INSTANTIATE_LOCK.lock().unwrap();
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut guard = RESOLVE_CALLBACK.lock().unwrap();
|
||||||
|
*guard = Some(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn c_cb(
|
||||||
|
context: Local<Context>,
|
||||||
|
specifier: Local<String>,
|
||||||
|
referrer: Local<Module>,
|
||||||
|
) -> *mut Module {
|
||||||
|
let guard = RESOLVE_CALLBACK.lock().unwrap();
|
||||||
|
let cb = guard.unwrap();
|
||||||
|
match cb(context, specifier, referrer) {
|
||||||
|
None => std::ptr::null_mut(),
|
||||||
|
Some(mut p) => &mut *p,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let r =
|
||||||
|
unsafe { v8__Module__InstantiateModule(self, context, c_cb) }.into();
|
||||||
|
drop(instantiate_guard);
|
||||||
|
r
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates the module and its dependencies.
|
/// Evaluates the module and its dependencies.
|
||||||
|
|
|
@ -2,7 +2,6 @@ use std::ops::Deref;
|
||||||
|
|
||||||
use crate::isolate::Isolate;
|
use crate::isolate::Isolate;
|
||||||
use crate::support::Opaque;
|
use crate::support::Opaque;
|
||||||
use crate::HandleScope;
|
|
||||||
use crate::Local;
|
use crate::Local;
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
|
|
||||||
|
@ -29,21 +28,21 @@ extern "C" {
|
||||||
fn v8__False(isolate: *mut Isolate) -> *mut Boolean;
|
fn v8__False(isolate: *mut Isolate) -> *mut Boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_null<'sc>(scope: &mut HandleScope<'sc>) -> Local<'sc, Primitive> {
|
pub fn new_null<'sc>(scope: &mut impl AsMut<Isolate>) -> Local<'sc, Primitive> {
|
||||||
unsafe { Local::from_raw(v8__Null(scope.as_mut())) }.unwrap()
|
unsafe { Local::from_raw(v8__Null(scope.as_mut())) }.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_undefined<'sc>(
|
pub fn new_undefined<'sc>(
|
||||||
scope: &mut HandleScope<'sc>,
|
scope: &mut impl AsMut<Isolate>,
|
||||||
) -> Local<'sc, Primitive> {
|
) -> Local<'sc, Primitive> {
|
||||||
unsafe { Local::from_raw(v8__Undefined(scope.as_mut())) }.unwrap()
|
unsafe { Local::from_raw(v8__Undefined(scope.as_mut())) }.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_true<'sc>(scope: &mut HandleScope<'sc>) -> Local<'sc, Boolean> {
|
pub fn new_true<'sc>(scope: &mut impl AsMut<Isolate>) -> Local<'sc, Boolean> {
|
||||||
unsafe { Local::from_raw(v8__True(scope.as_mut())) }.unwrap()
|
unsafe { Local::from_raw(v8__True(scope.as_mut())) }.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_false<'sc>(scope: &mut HandleScope<'sc>) -> Local<'sc, Boolean> {
|
pub fn new_false<'sc>(scope: &mut impl AsMut<Isolate>) -> Local<'sc, Boolean> {
|
||||||
unsafe { Local::from_raw(v8__False(scope.as_mut())) }.unwrap()
|
unsafe { Local::from_raw(v8__False(scope.as_mut())) }.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -209,25 +209,25 @@ fn array_buffer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn v8_str<'sc>(
|
fn v8_str<'sc>(
|
||||||
scope: &mut HandleScope<'sc>,
|
isolate: &mut impl AsMut<v8::Isolate>,
|
||||||
s: &str,
|
s: &str,
|
||||||
) -> v8::Local<'sc, v8::String> {
|
) -> v8::Local<'sc, v8::String> {
|
||||||
v8::String::new(scope, s).unwrap()
|
v8::String::new(isolate, s).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn eval<'sc>(
|
||||||
fn try_catch() {
|
|
||||||
fn eval<'sc>(
|
|
||||||
scope: &mut HandleScope<'sc>,
|
scope: &mut HandleScope<'sc>,
|
||||||
context: Local<v8::Context>,
|
context: Local<v8::Context>,
|
||||||
code: &'static str,
|
code: &'static str,
|
||||||
) -> Option<Local<'sc, v8::Value>> {
|
) -> Option<Local<'sc, v8::Value>> {
|
||||||
let source = v8_str(scope, code);
|
let source = v8_str(scope, code);
|
||||||
let mut script =
|
let mut script =
|
||||||
v8::Script::compile(&mut *scope, context, source, None).unwrap();
|
v8::Script::compile(&mut *scope, context, source, None).unwrap();
|
||||||
script.run(scope, context)
|
script.run(scope, context)
|
||||||
};
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn try_catch() {
|
||||||
let _g = setup();
|
let _g = setup();
|
||||||
let mut params = v8::Isolate::create_params();
|
let mut params = v8::Isolate::create_params();
|
||||||
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
|
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
|
||||||
|
@ -736,17 +736,18 @@ fn set_promise_reject_callback() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mock_script_origin<'sc>(
|
fn mock_script_origin<'sc>(
|
||||||
scope: &mut HandleScope<'sc>,
|
isolate: &mut impl AsMut<v8::Isolate>,
|
||||||
|
resource_name_: &str,
|
||||||
) -> v8::ScriptOrigin<'sc> {
|
) -> v8::ScriptOrigin<'sc> {
|
||||||
let resource_name = v8_str(scope, "foo.js");
|
let resource_name = v8_str(isolate, resource_name_);
|
||||||
let resource_line_offset = v8::Integer::new(scope, 0);
|
let resource_line_offset = v8::Integer::new(isolate, 0);
|
||||||
let resource_column_offset = v8::Integer::new(scope, 0);
|
let resource_column_offset = v8::Integer::new(isolate, 0);
|
||||||
let resource_is_shared_cross_origin = v8::new_true(scope);
|
let resource_is_shared_cross_origin = v8::new_true(isolate);
|
||||||
let script_id = v8::Integer::new(scope, 123);
|
let script_id = v8::Integer::new(isolate, 123);
|
||||||
let source_map_url = v8_str(scope, "source_map_url");
|
let source_map_url = v8_str(isolate, "source_map_url");
|
||||||
let resource_is_opaque = v8::new_true(scope);
|
let resource_is_opaque = v8::new_true(isolate);
|
||||||
let is_wasm = v8::new_false(scope);
|
let is_wasm = v8::new_false(isolate);
|
||||||
let is_module = v8::new_true(scope);
|
let is_module = v8::new_true(isolate);
|
||||||
v8::ScriptOrigin::new(
|
v8::ScriptOrigin::new(
|
||||||
resource_name.into(),
|
resource_name.into(),
|
||||||
resource_line_offset,
|
resource_line_offset,
|
||||||
|
@ -774,7 +775,7 @@ fn script_compiler_source() {
|
||||||
context.enter();
|
context.enter();
|
||||||
|
|
||||||
let source = "1+2";
|
let source = "1+2";
|
||||||
let script_origin = mock_script_origin(scope);
|
let script_origin = mock_script_origin(scope, "foo.js");
|
||||||
let source =
|
let source =
|
||||||
v8::script_compiler::Source::new(v8_str(scope, source), &script_origin);
|
v8::script_compiler::Source::new(v8_str(scope, source), &script_origin);
|
||||||
|
|
||||||
|
@ -810,10 +811,10 @@ fn module_instantiation_failures1() {
|
||||||
"import './foo.js';\n\
|
"import './foo.js';\n\
|
||||||
export {} from './bar.js';",
|
export {} from './bar.js';",
|
||||||
);
|
);
|
||||||
let origin = mock_script_origin(scope);
|
let origin = mock_script_origin(scope, "foo.js");
|
||||||
let source = v8::script_compiler::Source::new(source_text, &origin);
|
let source = v8::script_compiler::Source::new(source_text, &origin);
|
||||||
|
|
||||||
let module = v8::script_compiler::compile_module(
|
let mut module = v8::script_compiler::compile_module(
|
||||||
&isolate,
|
&isolate,
|
||||||
source,
|
source,
|
||||||
v8::script_compiler::CompileOptions::NoCompileOptions,
|
v8::script_compiler::CompileOptions::NoCompileOptions,
|
||||||
|
@ -839,7 +840,99 @@ fn module_instantiation_failures1() {
|
||||||
assert_eq!(1, loc.get_line_number());
|
assert_eq!(1, loc.get_line_number());
|
||||||
assert_eq!(15, loc.get_column_number());
|
assert_eq!(15, loc.get_column_number());
|
||||||
|
|
||||||
// TODO(ry) Instantiation should fail.
|
// Instantiation should fail.
|
||||||
|
{
|
||||||
|
let mut try_catch = v8::TryCatch::new(scope);
|
||||||
|
let tc = try_catch.enter();
|
||||||
|
fn resolve_callback(
|
||||||
|
mut context: v8::Local<v8::Context>,
|
||||||
|
_specifier: v8::Local<v8::String>,
|
||||||
|
_referrer: v8::Local<v8::Module>,
|
||||||
|
) -> Option<v8::Local<'static, v8::Module>> {
|
||||||
|
let isolate: &mut v8::Isolate = context.as_mut();
|
||||||
|
let e = v8_str(isolate, "boom");
|
||||||
|
isolate.throw_exception(e.into());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
let result = module.instantiate_module(context, resolve_callback);
|
||||||
|
assert!(result.is_none());
|
||||||
|
assert!(tc.has_caught());
|
||||||
|
assert!(tc
|
||||||
|
.exception()
|
||||||
|
.unwrap()
|
||||||
|
.strict_equals(v8_str(scope, "boom").into()));
|
||||||
|
assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status());
|
||||||
|
}
|
||||||
|
|
||||||
|
context.exit();
|
||||||
|
});
|
||||||
|
drop(locker);
|
||||||
|
isolate.exit();
|
||||||
|
drop(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn module_evaluation() {
|
||||||
|
let g = setup();
|
||||||
|
let mut params = v8::Isolate::create_params();
|
||||||
|
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
|
||||||
|
let mut isolate = v8::Isolate::new(params);
|
||||||
|
isolate.enter();
|
||||||
|
let mut locker = v8::Locker::new(&isolate);
|
||||||
|
v8::HandleScope::enter(&mut locker, |scope| {
|
||||||
|
let mut context = v8::Context::new(scope);
|
||||||
|
context.enter();
|
||||||
|
|
||||||
|
let source_text = v8_str(
|
||||||
|
scope,
|
||||||
|
"import 'Object.expando = 5';\n\
|
||||||
|
import 'Object.expando *= 2';",
|
||||||
|
);
|
||||||
|
let origin = mock_script_origin(scope, "foo.js");
|
||||||
|
let source = v8::script_compiler::Source::new(source_text, &origin);
|
||||||
|
|
||||||
|
let mut module = v8::script_compiler::compile_module(
|
||||||
|
&isolate,
|
||||||
|
source,
|
||||||
|
v8::script_compiler::CompileOptions::NoCompileOptions,
|
||||||
|
v8::script_compiler::NoCacheReason::NoReason,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status());
|
||||||
|
|
||||||
|
fn resolve_callback(
|
||||||
|
mut context: v8::Local<v8::Context>,
|
||||||
|
specifier: v8::Local<v8::String>,
|
||||||
|
_referrer: v8::Local<v8::Module>,
|
||||||
|
) -> Option<v8::Local<'static, v8::Module>> {
|
||||||
|
let isolate_: &mut v8::Isolate = context.as_mut();
|
||||||
|
let module_ = {
|
||||||
|
let mut escapable_scope = v8::EscapableHandleScope::new(isolate_);
|
||||||
|
let origin = mock_script_origin(isolate_, "module.js");
|
||||||
|
let source = v8::script_compiler::Source::new(specifier, &origin);
|
||||||
|
let module = v8::script_compiler::compile_module(
|
||||||
|
isolate_,
|
||||||
|
source,
|
||||||
|
v8::script_compiler::CompileOptions::NoCompileOptions,
|
||||||
|
v8::script_compiler::NoCacheReason::NoReason,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
escapable_scope.escape(cast(module))
|
||||||
|
};
|
||||||
|
Some(cast(module_))
|
||||||
|
}
|
||||||
|
let result = module.instantiate_module(context, resolve_callback);
|
||||||
|
assert!(result.unwrap());
|
||||||
|
assert_eq!(v8::ModuleStatus::Instantiated, module.get_status());
|
||||||
|
|
||||||
|
let result = module.evaluate(context);
|
||||||
|
assert!(result.is_some());
|
||||||
|
assert_eq!(v8::ModuleStatus::Evaluated, module.get_status());
|
||||||
|
|
||||||
|
let result = eval(scope, context, "Object.expando").unwrap();
|
||||||
|
assert!(result.is_number());
|
||||||
|
let expected = v8::Number::new(scope, 10.);
|
||||||
|
assert!(result.strict_equals(expected.into()));
|
||||||
|
|
||||||
context.exit();
|
context.exit();
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue