0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-11-24 15:19:31 -05:00

Add code cache API (#635)

This commit is contained in:
Heyang Zhou 2021-03-05 18:26:37 +08:00 committed by GitHub
parent 4937855c0c
commit be89cfc131
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 311 additions and 12 deletions

View file

@ -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());
}

View file

@ -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;

View file

@ -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 {

View file

@ -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 {

View file

@ -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()
}

View 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))
}
}
}

View file

@ -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)) }
}
}

View file

@ -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");
}