mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-26 00:59:28 -05:00
Add code cache API (#635)
This commit is contained in:
parent
4937855c0c
commit
be89cfc131
8 changed files with 311 additions and 12 deletions
|
@ -64,6 +64,30 @@ static_assert(sizeof(v8::CFunction) == sizeof(size_t) * 2,
|
|||
static_assert(sizeof(three_pointers_t) == sizeof(v8_inspector::StringView),
|
||||
"StringView size mismatch");
|
||||
|
||||
#if INTPTR_MAX == INT64_MAX // 64-bit platforms
|
||||
static_assert(sizeof(v8::ScriptCompiler::CachedData) == 24,
|
||||
"CachedData size mismatch");
|
||||
static_assert(offsetof(v8::ScriptCompiler::CachedData, data) == 0,
|
||||
"CachedData.data offset mismatch");
|
||||
static_assert(offsetof(v8::ScriptCompiler::CachedData, length) == 8,
|
||||
"CachedData.length offset mismatch");
|
||||
static_assert(offsetof(v8::ScriptCompiler::CachedData, rejected) == 12,
|
||||
"CachedData.rejected offset mismatch");
|
||||
static_assert(offsetof(v8::ScriptCompiler::CachedData, buffer_policy) == 16,
|
||||
"CachedData.buffer_policy offset mismatch");
|
||||
#else
|
||||
static_assert(sizeof(v8::ScriptCompiler::CachedData) == 16,
|
||||
"CachedData size mismatch");
|
||||
static_assert(offsetof(v8::ScriptCompiler::CachedData, data) == 0,
|
||||
"CachedData.data offset mismatch");
|
||||
static_assert(offsetof(v8::ScriptCompiler::CachedData, length) == 4,
|
||||
"CachedData.length offset mismatch");
|
||||
static_assert(offsetof(v8::ScriptCompiler::CachedData, rejected) == 8,
|
||||
"CachedData.rejected offset mismatch");
|
||||
static_assert(offsetof(v8::ScriptCompiler::CachedData, buffer_policy) == 12,
|
||||
"CachedData.buffer_policy offset mismatch");
|
||||
#endif
|
||||
|
||||
enum InternalSlots {
|
||||
kSlotDynamicImport = 0,
|
||||
kNumInternalSlots,
|
||||
|
@ -329,15 +353,32 @@ void v8__Global__Reset(const v8::Data* data) {
|
|||
|
||||
void v8__ScriptCompiler__Source__CONSTRUCT(
|
||||
uninit_t<v8::ScriptCompiler::Source>* buf, const v8::String& source_string,
|
||||
const v8::ScriptOrigin& origin) {
|
||||
const v8::ScriptOrigin& origin,
|
||||
v8::ScriptCompiler::CachedData* cached_data) {
|
||||
construct_in_place<v8::ScriptCompiler::Source>(
|
||||
buf, ptr_to_local(&source_string), origin);
|
||||
buf, ptr_to_local(&source_string), origin, cached_data);
|
||||
}
|
||||
|
||||
void v8__ScriptCompiler__Source__DESTRUCT(v8::ScriptCompiler::Source* self) {
|
||||
self->~Source();
|
||||
}
|
||||
|
||||
v8::ScriptCompiler::CachedData* v8__ScriptCompiler__CachedData__NEW(
|
||||
const uint8_t* data, int length) {
|
||||
return new v8::ScriptCompiler::CachedData(
|
||||
data, length, v8::ScriptCompiler::CachedData::BufferNotOwned);
|
||||
}
|
||||
|
||||
void v8__ScriptCompiler__CachedData__DELETE(
|
||||
v8::ScriptCompiler::CachedData* self) {
|
||||
delete self;
|
||||
}
|
||||
|
||||
const v8::ScriptCompiler::CachedData* v8__ScriptCompiler__Source__GetCachedData(
|
||||
const v8::ScriptCompiler::Source* source) {
|
||||
return source->GetCachedData();
|
||||
}
|
||||
|
||||
const v8::Module* v8__ScriptCompiler__CompileModule(
|
||||
v8::Isolate* isolate, v8::ScriptCompiler::Source* source,
|
||||
v8::ScriptCompiler::CompileOptions options,
|
||||
|
@ -1573,6 +1614,17 @@ const v8::Script* v8__UnboundScript__BindToCurrentContext(
|
|||
return local_to_ptr(ptr_to_local(&unbound_script)->BindToCurrentContext());
|
||||
}
|
||||
|
||||
v8::ScriptCompiler::CachedData* v8__UnboundScript__CreateCodeCache(
|
||||
const v8::UnboundScript& unbound_script) {
|
||||
return v8::ScriptCompiler::CreateCodeCache(ptr_to_local(&unbound_script));
|
||||
}
|
||||
|
||||
v8::ScriptCompiler::CachedData* v8__UnboundModuleScript__CreateCodeCache(
|
||||
const v8::UnboundModuleScript& unbound_module_script) {
|
||||
return v8::ScriptCompiler::CreateCodeCache(
|
||||
ptr_to_local(&unbound_module_script));
|
||||
}
|
||||
|
||||
const v8::Value* v8__Script__Run(const v8::Script& script,
|
||||
const v8::Context& context) {
|
||||
return maybe_local_to_ptr(ptr_to_local(&script)->Run(ptr_to_local(&context)));
|
||||
|
@ -2119,7 +2171,13 @@ MaybeBool v8__Module__SetSyntheticModuleExport(const v8::Module& self,
|
|||
isolate, ptr_to_local(export_name), ptr_to_local(export_value)));
|
||||
}
|
||||
|
||||
const v8::String* v8__ModuleRequest__GetSpecifier(const v8::ModuleRequest& self) {
|
||||
const v8::UnboundModuleScript* v8__Module__GetUnboundModuleScript(
|
||||
const v8::Module& self) {
|
||||
return local_to_ptr(ptr_to_local(&self)->GetUnboundModuleScript());
|
||||
}
|
||||
|
||||
const v8::String* v8__ModuleRequest__GetSpecifier(
|
||||
const v8::ModuleRequest& self) {
|
||||
return local_to_ptr(self.GetSpecifier());
|
||||
}
|
||||
|
||||
|
@ -2127,7 +2185,8 @@ int v8__ModuleRequest__GetSourceOffset(const v8::ModuleRequest& self) {
|
|||
return self.GetSourceOffset();
|
||||
}
|
||||
|
||||
const v8::FixedArray* v8__ModuleRequest__GetImportAssertions(const v8::ModuleRequest& self) {
|
||||
const v8::FixedArray* v8__ModuleRequest__GetImportAssertions(
|
||||
const v8::ModuleRequest& self) {
|
||||
return local_to_ptr(self.GetImportAssertions());
|
||||
}
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ mod support;
|
|||
mod symbol;
|
||||
mod template;
|
||||
mod typed_array;
|
||||
mod unbound_module_script;
|
||||
mod unbound_script;
|
||||
mod value;
|
||||
mod value_deserializer;
|
||||
|
@ -125,6 +126,7 @@ pub use scope::EscapableHandleScope;
|
|||
pub use scope::HandleScope;
|
||||
pub use scope::TryCatch;
|
||||
pub use script::ScriptOrigin;
|
||||
pub use script_compiler::CachedData;
|
||||
pub use snapshot::FunctionCodeHandling;
|
||||
pub use snapshot::SnapshotCreator;
|
||||
pub use snapshot::StartupData;
|
||||
|
|
|
@ -18,6 +18,7 @@ use crate::Local;
|
|||
use crate::Module;
|
||||
use crate::ModuleRequest;
|
||||
use crate::String;
|
||||
use crate::UnboundModuleScript;
|
||||
use crate::Value;
|
||||
|
||||
/// Called during Module::instantiate_module. Provided with arguments:
|
||||
|
@ -177,6 +178,9 @@ extern "C" {
|
|||
export_name: *const String,
|
||||
export_value: *const Value,
|
||||
) -> MaybeBool;
|
||||
fn v8__Module__GetUnboundModuleScript(
|
||||
this: *const Module,
|
||||
) -> *const UnboundModuleScript;
|
||||
fn v8__Location__GetLineNumber(this: *const Location) -> int;
|
||||
fn v8__Location__GetColumnNumber(this: *const Location) -> int;
|
||||
fn v8__ModuleRequest__GetSpecifier(
|
||||
|
@ -422,6 +426,17 @@ impl Module {
|
|||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn get_unbound_module_script<'s>(
|
||||
&self,
|
||||
scope: &mut HandleScope<'s>,
|
||||
) -> Local<'s, UnboundModuleScript> {
|
||||
unsafe {
|
||||
scope
|
||||
.cast_local(|_| v8__Module__GetUnboundModuleScript(self))
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Module {
|
||||
|
|
|
@ -1,21 +1,29 @@
|
|||
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
|
||||
use std::mem::MaybeUninit;
|
||||
use std::{marker::PhantomData, mem::MaybeUninit};
|
||||
|
||||
use crate::HandleScope;
|
||||
use crate::Isolate;
|
||||
use crate::Local;
|
||||
use crate::Module;
|
||||
use crate::ScriptOrigin;
|
||||
use crate::String;
|
||||
use crate::{HandleScope, UniqueRef};
|
||||
|
||||
extern "C" {
|
||||
fn v8__ScriptCompiler__Source__CONSTRUCT(
|
||||
buf: *mut MaybeUninit<Source>,
|
||||
source_string: *const String,
|
||||
origin: *const ScriptOrigin,
|
||||
cached_data: *mut CachedData,
|
||||
);
|
||||
fn v8__ScriptCompiler__Source__DESTRUCT(this: *mut Source);
|
||||
|
||||
fn v8__ScriptCompiler__Source__GetCachedData<'a>(
|
||||
this: *const Source,
|
||||
) -> *const CachedData<'a>;
|
||||
fn v8__ScriptCompiler__CachedData__NEW<'a>(
|
||||
data: *const u8,
|
||||
length: i32,
|
||||
) -> *mut CachedData<'a>;
|
||||
fn v8__ScriptCompiler__CachedData__DELETE<'a>(this: *mut CachedData<'a>);
|
||||
fn v8__ScriptCompiler__CompileModule(
|
||||
isolate: *mut Isolate,
|
||||
source: *mut Source,
|
||||
|
@ -29,15 +37,87 @@ extern "C" {
|
|||
#[derive(Debug)]
|
||||
pub struct Source([usize; 8]);
|
||||
|
||||
/// Compilation data that the embedder can cache and pass back to speed up future
|
||||
/// compilations. The data is produced if the CompilerOptions passed to the compilation
|
||||
/// functions in ScriptCompiler contains produce_data_to_cache = true. The data to cache
|
||||
/// can then can be retrieved from UnboundScript.
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct CachedData<'a> {
|
||||
data: *const u8,
|
||||
length: i32,
|
||||
rejected: bool,
|
||||
buffer_policy: BufferPolicy,
|
||||
_phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> Drop for CachedData<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
v8__ScriptCompiler__CachedData__DELETE(self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> CachedData<'a> {
|
||||
pub fn new(data: &'a [u8]) -> UniqueRef<Self> {
|
||||
unsafe {
|
||||
UniqueRef::from_raw(v8__ScriptCompiler__CachedData__NEW(
|
||||
data.as_ptr(),
|
||||
data.len() as i32,
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::ops::Deref for CachedData<'a> {
|
||||
type Target = [u8];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { std::slice::from_raw_parts(self.data, self.length as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
enum BufferPolicy {
|
||||
BufferNotOwned = 0,
|
||||
BufferOwned,
|
||||
}
|
||||
|
||||
impl Source {
|
||||
// TODO(ry) cached_data
|
||||
pub fn new(source_string: Local<String>, origin: &ScriptOrigin) -> Self {
|
||||
let mut buf = MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
v8__ScriptCompiler__Source__CONSTRUCT(&mut buf, &*source_string, origin);
|
||||
v8__ScriptCompiler__Source__CONSTRUCT(
|
||||
&mut buf,
|
||||
&*source_string,
|
||||
origin,
|
||||
std::ptr::null_mut(),
|
||||
);
|
||||
buf.assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_with_cached_data(
|
||||
source_string: Local<String>,
|
||||
origin: &ScriptOrigin,
|
||||
cached_data: UniqueRef<CachedData>,
|
||||
) -> Self {
|
||||
let mut buf = MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
v8__ScriptCompiler__Source__CONSTRUCT(
|
||||
&mut buf,
|
||||
&*source_string,
|
||||
origin,
|
||||
cached_data.into_raw(), // Source constructor takes ownership.
|
||||
);
|
||||
buf.assume_init()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_cached_data(&self) -> &CachedData {
|
||||
unsafe { &*v8__ScriptCompiler__Source__GetCachedData(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Source {
|
||||
|
|
|
@ -106,12 +106,12 @@ impl<T> From<UniqueRef<T>> for UniquePtr<T> {
|
|||
pub struct UniqueRef<T: ?Sized>(NonNull<T>);
|
||||
|
||||
impl<T> UniqueRef<T> {
|
||||
unsafe fn try_from_raw(ptr: *mut T) -> Option<Self> {
|
||||
pub(crate) unsafe fn try_from_raw(ptr: *mut T) -> Option<Self> {
|
||||
assert_unique_ptr_layout_compatible::<Self, T>();
|
||||
NonNull::new(ptr).map(Self)
|
||||
}
|
||||
|
||||
pub unsafe fn from_raw(ptr: *mut T) -> Self {
|
||||
pub(crate) unsafe fn from_raw(ptr: *mut T) -> Self {
|
||||
assert_unique_ptr_layout_compatible::<Self, T>();
|
||||
Self::try_from_raw(ptr).unwrap()
|
||||
}
|
||||
|
|
20
src/unbound_module_script.rs
Normal file
20
src/unbound_module_script.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use crate::CachedData;
|
||||
use crate::UnboundModuleScript;
|
||||
use crate::UniqueRef;
|
||||
|
||||
extern "C" {
|
||||
fn v8__UnboundModuleScript__CreateCodeCache(
|
||||
script: *const UnboundModuleScript,
|
||||
) -> *mut CachedData<'static>;
|
||||
}
|
||||
|
||||
impl UnboundModuleScript {
|
||||
/// Creates and returns code cache for the specified unbound_module_script.
|
||||
/// This will return nullptr if the script cannot be serialized. The
|
||||
/// CachedData returned by this function should be owned by the caller.
|
||||
pub fn create_code_cache(&self) -> Option<UniqueRef<CachedData<'static>>> {
|
||||
unsafe {
|
||||
UniqueRef::try_from_raw(v8__UnboundModuleScript__CreateCodeCache(self))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +1,16 @@
|
|||
use crate::HandleScope;
|
||||
use crate::CachedData;
|
||||
use crate::Local;
|
||||
use crate::Script;
|
||||
use crate::UnboundScript;
|
||||
use crate::{HandleScope, UniqueRef};
|
||||
|
||||
extern "C" {
|
||||
fn v8__UnboundScript__BindToCurrentContext(
|
||||
script: *const UnboundScript,
|
||||
) -> *const Script;
|
||||
fn v8__UnboundScript__CreateCodeCache(
|
||||
script: *const UnboundScript,
|
||||
) -> *mut CachedData<'static>;
|
||||
}
|
||||
|
||||
impl UnboundScript {
|
||||
|
@ -20,4 +24,11 @@ impl UnboundScript {
|
|||
}
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Creates and returns code cache for the specified unbound_script.
|
||||
/// This will return nullptr if the script cannot be serialized. The
|
||||
/// CachedData returned by this function should be owned by the caller.
|
||||
pub fn create_code_cache(&self) -> Option<UniqueRef<CachedData<'static>>> {
|
||||
unsafe { UniqueRef::try_from_raw(v8__UnboundScript__CreateCodeCache(self)) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4782,3 +4782,115 @@ fn icu_collator() {
|
|||
let script = v8::Script::compile(scope, source, None).unwrap();
|
||||
assert!(script.run(scope).is_some());
|
||||
}
|
||||
|
||||
fn create_module<'s>(
|
||||
scope: &mut v8::HandleScope<'s, v8::Context>,
|
||||
source: &str,
|
||||
code_cache: Option<v8::UniqueRef<v8::CachedData>>,
|
||||
options: v8::script_compiler::CompileOptions,
|
||||
) -> v8::Local<'s, v8::Module> {
|
||||
let source = v8::String::new(scope, source).unwrap();
|
||||
let resource_name = v8::String::new(scope, "<resource>").unwrap();
|
||||
let source_map_url = v8::undefined(scope);
|
||||
let script_origin = v8::ScriptOrigin::new(
|
||||
scope,
|
||||
resource_name.into(),
|
||||
0,
|
||||
0,
|
||||
false,
|
||||
0,
|
||||
source_map_url.into(),
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
);
|
||||
let source = match code_cache {
|
||||
Some(x) => v8::script_compiler::Source::new_with_cached_data(
|
||||
source,
|
||||
&script_origin,
|
||||
x,
|
||||
),
|
||||
None => v8::script_compiler::Source::new(source, &script_origin),
|
||||
};
|
||||
let module = v8::script_compiler::compile_module2(
|
||||
scope,
|
||||
source,
|
||||
options,
|
||||
v8::script_compiler::NoCacheReason::NoReason,
|
||||
)
|
||||
.unwrap();
|
||||
module
|
||||
}
|
||||
|
||||
fn create_unbound_module_script<'s>(
|
||||
scope: &mut v8::HandleScope<'s, v8::Context>,
|
||||
source: &str,
|
||||
code_cache: Option<v8::UniqueRef<v8::CachedData>>,
|
||||
) -> v8::Local<'s, v8::UnboundModuleScript> {
|
||||
let module = create_module(
|
||||
scope,
|
||||
source,
|
||||
code_cache,
|
||||
v8::script_compiler::CompileOptions::NoCompileOptions,
|
||||
);
|
||||
module.get_unbound_module_script(scope)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unbound_module_script_conversion() {
|
||||
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 mut scope = v8::ContextScope::new(scope, context);
|
||||
create_unbound_module_script(&mut scope, "'Hello ' + value", None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn code_cache() {
|
||||
fn resolve_callback<'a>(
|
||||
_context: v8::Local<'a, v8::Context>,
|
||||
_specifier: v8::Local<'a, v8::String>,
|
||||
_import_assertions: v8::Local<'a, v8::FixedArray>,
|
||||
_referrer: v8::Local<'a, v8::Module>,
|
||||
) -> Option<v8::Local<'a, v8::Module>> {
|
||||
None
|
||||
}
|
||||
|
||||
const CODE: &str = "export const hello = 'world';";
|
||||
let _setup_guard = setup();
|
||||
|
||||
let code_cache = {
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
let context = v8::Context::new(scope);
|
||||
let mut scope = v8::ContextScope::new(scope, context);
|
||||
let unbound_module_script =
|
||||
create_unbound_module_script(&mut scope, CODE, None);
|
||||
unbound_module_script.create_code_cache().unwrap().to_vec()
|
||||
};
|
||||
|
||||
let isolate = &mut v8::Isolate::new(Default::default());
|
||||
let scope = &mut v8::HandleScope::new(isolate);
|
||||
let context = v8::Context::new(scope);
|
||||
let mut scope = v8::ContextScope::new(scope, context);
|
||||
let module = create_module(
|
||||
&mut scope,
|
||||
CODE,
|
||||
Some(v8::CachedData::new(&code_cache)),
|
||||
v8::script_compiler::CompileOptions::ConsumeCodeCache,
|
||||
);
|
||||
let mut scope = v8::HandleScope::new(&mut scope);
|
||||
module
|
||||
.instantiate_module(&mut scope, resolve_callback)
|
||||
.unwrap();
|
||||
module.evaluate(&mut scope).unwrap();
|
||||
let top =
|
||||
v8::Local::<v8::Object>::try_from(module.get_module_namespace()).unwrap();
|
||||
|
||||
let key = v8::String::new(&mut scope, "hello").unwrap();
|
||||
let value =
|
||||
v8::Local::<v8::String>::try_from(top.get(&mut scope, key.into()).unwrap())
|
||||
.unwrap();
|
||||
assert_eq!(&value.to_rust_string_lossy(&mut scope), "world");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue