mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-11-22 04:40:01 +00:00
Add synthetic module support (#441)
This commit is contained in:
parent
6b2c7a56a7
commit
6d5686cd7c
@ -1736,6 +1736,35 @@ const v8::Value* v8__Module__Evaluate(const v8::Module& self,
|
|||||||
ptr_to_local(&self)->Evaluate(ptr_to_local(&context)));
|
ptr_to_local(&self)->Evaluate(ptr_to_local(&context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool v8__Module__IsSourceTextModule(const v8::Module& self) {
|
||||||
|
return ptr_to_local(&self)->IsSourceTextModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool v8__Module__IsSyntheticModule(const v8::Module&self) {
|
||||||
|
return ptr_to_local(&self)->IsSyntheticModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
const v8::Module* v8__Module__CreateSyntheticModule(
|
||||||
|
v8::Isolate* isolate, const v8::String* module_name,
|
||||||
|
size_t export_names_len, const v8::String* export_names_raw[],
|
||||||
|
v8::Module::SyntheticModuleEvaluationSteps evaluation_steps) {
|
||||||
|
std::vector<v8::Local<v8::String>> export_names{};
|
||||||
|
for (size_t i = 0; i < export_names_len; i += 1) {
|
||||||
|
export_names.push_back(ptr_to_local(export_names_raw[i]));
|
||||||
|
}
|
||||||
|
return local_to_ptr(v8::Module::CreateSyntheticModule(
|
||||||
|
isolate, ptr_to_local(module_name), export_names,
|
||||||
|
evaluation_steps));
|
||||||
|
}
|
||||||
|
|
||||||
|
MaybeBool v8__Module__SetSyntheticModuleExport(const v8::Module& self,
|
||||||
|
v8::Isolate* isolate,
|
||||||
|
const v8::String* export_name,
|
||||||
|
const v8::Value* export_value) {
|
||||||
|
return maybe_to_maybe_bool(ptr_to_local(&self)->SetSyntheticModuleExport(
|
||||||
|
isolate, ptr_to_local(export_name), ptr_to_local(export_value)));
|
||||||
|
}
|
||||||
|
|
||||||
using HeapSnapshotCallback = bool (*)(void*, const char*, size_t);
|
using HeapSnapshotCallback = bool (*)(void*, const char*, size_t);
|
||||||
|
|
||||||
void v8__HeapProfiler__TakeHeapSnapshot(v8::Isolate* isolate,
|
void v8__HeapProfiler__TakeHeapSnapshot(v8::Isolate* isolate,
|
||||||
|
120
src/module.rs
120
src/module.rs
@ -10,6 +10,7 @@ use crate::support::ToCFn;
|
|||||||
use crate::support::UnitType;
|
use crate::support::UnitType;
|
||||||
use crate::Context;
|
use crate::Context;
|
||||||
use crate::HandleScope;
|
use crate::HandleScope;
|
||||||
|
use crate::Isolate;
|
||||||
use crate::Local;
|
use crate::Local;
|
||||||
use crate::Module;
|
use crate::Module;
|
||||||
use crate::String;
|
use crate::String;
|
||||||
@ -82,6 +83,48 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// System V AMD64 ABI: Local<Value> returned in a register.
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
pub type SyntheticModuleEvaluationSteps<'a> =
|
||||||
|
extern "C" fn(Local<'a, Context>, Local<'a, Module>) -> *const Value;
|
||||||
|
|
||||||
|
// Windows x64 ABI: Local<Value> returned on the stack.
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub type SyntheticModuleEvaluationSteps<'a> =
|
||||||
|
extern "C" fn(
|
||||||
|
*mut *const Value,
|
||||||
|
Local<'a, Context>,
|
||||||
|
Local<'a, Module>,
|
||||||
|
) -> *mut *const Value;
|
||||||
|
|
||||||
|
impl<'a, F> MapFnFrom<F> for SyntheticModuleEvaluationSteps<'a>
|
||||||
|
where
|
||||||
|
F: UnitType
|
||||||
|
+ Fn(Local<'a, Context>, Local<'a, Module>) -> Option<Local<'a, Value>>,
|
||||||
|
{
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
fn mapping() -> Self {
|
||||||
|
let f = |context, module| {
|
||||||
|
(F::get())(context, module)
|
||||||
|
.map(|r| -> *const Value { &*r })
|
||||||
|
.unwrap_or(null())
|
||||||
|
};
|
||||||
|
f.to_c_fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn mapping() -> Self {
|
||||||
|
let f = |ret_ptr, context, module| {
|
||||||
|
let r = (F::get())(context, module)
|
||||||
|
.map(|r| -> *const Value { &*r })
|
||||||
|
.unwrap_or(null());
|
||||||
|
unsafe { std::ptr::write(ret_ptr, r) }; // Write result to stack.
|
||||||
|
ret_ptr // Return stack pointer to the return value.
|
||||||
|
};
|
||||||
|
f.to_c_fn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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) -> *const Value;
|
fn v8__Module__GetException(this: *const Module) -> *const Value;
|
||||||
@ -104,6 +147,21 @@ extern "C" {
|
|||||||
this: *const Module,
|
this: *const Module,
|
||||||
context: *const Context,
|
context: *const Context,
|
||||||
) -> *const Value;
|
) -> *const Value;
|
||||||
|
fn v8__Module__IsSourceTextModule(this: *const Module) -> bool;
|
||||||
|
fn v8__Module__IsSyntheticModule(this: *const Module) -> bool;
|
||||||
|
fn v8__Module__CreateSyntheticModule(
|
||||||
|
isolate: *const Isolate,
|
||||||
|
module_name: *const String,
|
||||||
|
export_names_len: usize,
|
||||||
|
export_names_raw: *const *const String,
|
||||||
|
evaluation_steps: SyntheticModuleEvaluationSteps,
|
||||||
|
) -> *const Module;
|
||||||
|
fn v8__Module__SetSyntheticModuleExport(
|
||||||
|
this: *const Module,
|
||||||
|
isolate: *const Isolate,
|
||||||
|
export_name: *const String,
|
||||||
|
export_value: *const Value,
|
||||||
|
) -> MaybeBool;
|
||||||
fn v8__Location__GetLineNumber(this: *const Location) -> int;
|
fn v8__Location__GetLineNumber(this: *const Location) -> int;
|
||||||
fn v8__Location__GetColumnNumber(this: *const Location) -> int;
|
fn v8__Location__GetColumnNumber(this: *const Location) -> int;
|
||||||
}
|
}
|
||||||
@ -236,4 +294,66 @@ impl Module {
|
|||||||
.cast_local(|sd| v8__Module__Evaluate(&*self, sd.get_current_context()))
|
.cast_local(|sd| v8__Module__Evaluate(&*self, sd.get_current_context()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns whether the module is a SourceTextModule.
|
||||||
|
pub fn is_source_text_module(&self) -> bool {
|
||||||
|
unsafe { v8__Module__IsSourceTextModule(&*self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns whether the module is a SyntheticModule.
|
||||||
|
pub fn is_synthetic_module(&self) -> bool {
|
||||||
|
unsafe { v8__Module__IsSyntheticModule(&*self) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new SyntheticModule with the specified export names, where
|
||||||
|
/// evaluation_steps will be executed upon module evaluation.
|
||||||
|
/// export_names must not contain duplicates.
|
||||||
|
/// module_name is used solely for logging/debugging and doesn't affect module
|
||||||
|
/// behavior.
|
||||||
|
pub fn create_synthetic_module<'s, 'a>(
|
||||||
|
scope: &mut HandleScope<'s>,
|
||||||
|
module_name: Local<String>,
|
||||||
|
export_names: &[Local<String>],
|
||||||
|
evaluation_steps: impl MapFnTo<SyntheticModuleEvaluationSteps<'a>>,
|
||||||
|
) -> Local<'s, Module> {
|
||||||
|
let export_names = Local::slice_into_raw(export_names);
|
||||||
|
let export_names_len = export_names.len();
|
||||||
|
let export_names = export_names.as_ptr();
|
||||||
|
unsafe {
|
||||||
|
scope
|
||||||
|
.cast_local(|sd| {
|
||||||
|
v8__Module__CreateSyntheticModule(
|
||||||
|
sd.get_isolate_ptr(),
|
||||||
|
&*module_name,
|
||||||
|
export_names_len,
|
||||||
|
export_names,
|
||||||
|
evaluation_steps.map_fn_to(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set this module's exported value for the name export_name to the specified
|
||||||
|
/// export_value. This method must be called only on Modules created via
|
||||||
|
/// create_synthetic_module. An error will be thrown if export_name is not one
|
||||||
|
/// of the export_names that were passed in that create_synthetic_module call.
|
||||||
|
/// Returns Some(true) on success, None if an error was thrown.
|
||||||
|
#[must_use]
|
||||||
|
pub fn set_synthetic_module_export(
|
||||||
|
&self,
|
||||||
|
scope: &mut HandleScope,
|
||||||
|
export_name: Local<String>,
|
||||||
|
export_value: Local<Value>,
|
||||||
|
) -> Option<bool> {
|
||||||
|
unsafe {
|
||||||
|
v8__Module__SetSyntheticModuleExport(
|
||||||
|
&*self,
|
||||||
|
scope.get_isolate_ptr(),
|
||||||
|
&*export_name,
|
||||||
|
&*export_value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1818,6 +1818,8 @@ fn module_evaluation() {
|
|||||||
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(scope, source).unwrap();
|
let module = v8::script_compiler::compile_module(scope, source).unwrap();
|
||||||
|
assert!(module.is_source_text_module());
|
||||||
|
assert!(!module.is_synthetic_module());
|
||||||
assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status());
|
assert_eq!(v8::ModuleStatus::Uninstantiated, module.get_status());
|
||||||
|
|
||||||
let result = module
|
let result = module
|
||||||
@ -3409,3 +3411,75 @@ fn heap_statistics() {
|
|||||||
scope.get_heap_statistics(&mut s);
|
scope.get_heap_statistics(&mut s);
|
||||||
assert_ne!(s.number_of_native_contexts(), 0);
|
assert_ne!(s.number_of_native_contexts(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn synthetic_evaluation_steps<'a>(
|
||||||
|
context: v8::Local<'a, v8::Context>,
|
||||||
|
module: v8::Local<v8::Module>,
|
||||||
|
) -> Option<v8::Local<'a, v8::Value>> {
|
||||||
|
let scope = &mut unsafe { v8::CallbackScope::new(context) };
|
||||||
|
let mut set = |name, value| {
|
||||||
|
let name = v8::String::new(scope, name).unwrap();
|
||||||
|
let value = v8::Number::new(scope, value).into();
|
||||||
|
module
|
||||||
|
.set_synthetic_module_export(scope, name, value)
|
||||||
|
.unwrap();
|
||||||
|
};
|
||||||
|
set("a", 1.0);
|
||||||
|
set("b", 2.0);
|
||||||
|
|
||||||
|
{
|
||||||
|
let scope = &mut v8::TryCatch::new(scope);
|
||||||
|
let name = v8::String::new(scope, "does not exist").unwrap();
|
||||||
|
let value = v8::undefined(scope).into();
|
||||||
|
assert!(module.set_synthetic_module_export(scope, name, value) == None);
|
||||||
|
assert!(scope.has_caught());
|
||||||
|
scope.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(v8::undefined(scope).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn synthetic_module() {
|
||||||
|
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 export_names = [
|
||||||
|
v8::String::new(scope, "a").unwrap(),
|
||||||
|
v8::String::new(scope, "b").unwrap(),
|
||||||
|
];
|
||||||
|
let module_name = v8::String::new(scope, "synthetic module").unwrap();
|
||||||
|
let module = v8::Module::create_synthetic_module(
|
||||||
|
scope,
|
||||||
|
module_name,
|
||||||
|
&export_names,
|
||||||
|
synthetic_evaluation_steps,
|
||||||
|
);
|
||||||
|
assert!(!module.is_source_text_module());
|
||||||
|
assert!(module.is_synthetic_module());
|
||||||
|
assert_eq!(module.get_status(), v8::ModuleStatus::Uninstantiated);
|
||||||
|
|
||||||
|
module
|
||||||
|
.instantiate_module(scope, unexpected_module_resolve_callback)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(module.get_status(), v8::ModuleStatus::Instantiated);
|
||||||
|
|
||||||
|
module.evaluate(scope).unwrap();
|
||||||
|
assert_eq!(module.get_status(), v8::ModuleStatus::Evaluated);
|
||||||
|
|
||||||
|
let ns =
|
||||||
|
v8::Local::<v8::Object>::try_from(module.get_module_namespace()).unwrap();
|
||||||
|
|
||||||
|
let mut check = |name, value| {
|
||||||
|
let name = v8::String::new(scope, name).unwrap().into();
|
||||||
|
let value = v8::Number::new(scope, value).into();
|
||||||
|
assert!(ns.get(scope, name).unwrap().strict_equals(value));
|
||||||
|
};
|
||||||
|
check("a", 1.0);
|
||||||
|
check("b", 2.0);
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user