0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-12-26 00:59:28 -05:00

first pass at snapshots (#122)

Creating a snapshot leaks memory. We will address this in future work.
This commit is contained in:
Bartek Iwańczuk 2019-12-24 14:03:32 +01:00 committed by Ry Dahl
parent b21b67d5ae
commit 1507a897de
5 changed files with 195 additions and 2 deletions

View file

@ -36,6 +36,9 @@ static_assert(sizeof(v8::TryCatch) == sizeof(size_t) * 6,
static_assert(sizeof(v8::Location) == sizeof(size_t) * 1, static_assert(sizeof(v8::Location) == sizeof(size_t) * 1,
"Location size mismatch"); "Location size mismatch");
static_assert(sizeof(v8::SnapshotCreator) == sizeof(size_t) * 1,
"SnapshotCreator size mismatch");
extern "C" { extern "C" {
void v8__V8__SetFlagsFromCommandLine(int* argc, char** argv) { void v8__V8__SetFlagsFromCommandLine(int* argc, char** argv) {
@ -111,6 +114,12 @@ void v8__Isolate__CreateParams__SET__array_buffer_allocator(
self.array_buffer_allocator = value; self.array_buffer_allocator = value;
} }
// This function does not take ownership of the StartupData.
void v8__Isolate__CreateParams__SET__snapshot_blob(
v8::Isolate::CreateParams& self, v8::StartupData* snapshot_blob) {
self.snapshot_blob = snapshot_blob;
}
void v8__HandleScope__CONSTRUCT(uninit_t<v8::HandleScope>& buf, void v8__HandleScope__CONSTRUCT(uninit_t<v8::HandleScope>& buf,
v8::Isolate* isolate) { v8::Isolate* isolate) {
construct_in_place<v8::HandleScope>(buf, isolate); construct_in_place<v8::HandleScope>(buf, isolate);
@ -325,7 +334,8 @@ size_t v8__ArrayBufferView__ByteOffset(v8::ArrayBufferView& self) {
return self.ByteOffset(); return self.ByteOffset();
} }
size_t v8__ArrayBufferView__CopyContents(v8::ArrayBufferView& self, void* dest, int byte_length) { size_t v8__ArrayBufferView__CopyContents(v8::ArrayBufferView& self, void* dest,
int byte_length) {
return self.CopyContents(dest, byte_length); return self.CopyContents(dest, byte_length);
} }
@ -626,6 +636,29 @@ void v8__PropertyCallbackInfo__GetReturnValue(
*out = self.GetReturnValue(); *out = self.GetReturnValue();
} }
void v8__SnapshotCreator__CONSTRUCT(uninit_t<v8::SnapshotCreator>& buf) {
construct_in_place<v8::SnapshotCreator>(buf);
}
void v8__SnapshotCreator__DESTRUCT(v8::SnapshotCreator& self) {
self.~SnapshotCreator();
}
v8::Isolate* v8__SnapshotCreator__GetIsolate(v8::SnapshotCreator& self) {
return self.GetIsolate();
}
void v8__SnapshotCreator__SetDefaultContext(v8::SnapshotCreator& self,
v8::Local<v8::Context> context) {
self.SetDefaultContext(context);
}
v8::StartupData v8__SnapshotCreator__CreateBlob(
v8::SnapshotCreator* self,
v8::SnapshotCreator::FunctionCodeHandling function_code_handling) {
return self->CreateBlob(function_code_handling);
}
v8::Platform* v8__platform__NewDefaultPlatform() { v8::Platform* v8__platform__NewDefaultPlatform() {
// TODO: support optional arguments. // TODO: support optional arguments.
return v8::platform::NewDefaultPlatform().release(); return v8::platform::NewDefaultPlatform().release();

View file

@ -6,6 +6,7 @@ use crate::support::Opaque;
use crate::support::UniqueRef; use crate::support::UniqueRef;
use crate::Local; use crate::Local;
use crate::Message; use crate::Message;
use crate::StartupData;
use crate::Value; use crate::Value;
use std::ops::Deref; use std::ops::Deref;
use std::ops::DerefMut; use std::ops::DerefMut;
@ -44,7 +45,10 @@ extern "C" {
this: &mut CreateParams, this: &mut CreateParams,
value: *mut Allocator, value: *mut Allocator,
); );
fn v8__Isolate__CreateParams__SET__snapshot_blob(
this: &mut CreateParams,
snapshot_blob: *mut StartupData,
);
} }
#[repr(C)] #[repr(C)]
@ -199,6 +203,25 @@ impl CreateParams {
) )
}; };
} }
/// Hand startup data to V8, in case the embedder has chosen to build
/// V8 with external startup data.
///
/// Note:
/// - By default the startup data is linked into the V8 library, in which
/// case this function is not meaningful.
/// - If this needs to be called, it needs to be called before V8
/// tries to make use of its built-ins.
/// - To avoid unnecessary copies of data, V8 will point directly into the
/// given data blob, so pretty please keep it around until V8 exit.
/// - Compression of the startup blob might be useful, but needs to
/// handled entirely on the embedders' side.
/// - The call will abort if the data is invalid.
pub fn set_snapshot_blob(&mut self, snapshot_blob: &mut StartupData) {
unsafe {
v8__Isolate__CreateParams__SET__snapshot_blob(self, &mut *snapshot_blob)
};
}
} }
impl Delete for CreateParams { impl Delete for CreateParams {

View file

@ -27,6 +27,7 @@ mod promise;
mod property; mod property;
mod script; mod script;
mod script_or_module; mod script_or_module;
mod snapshot;
mod string; mod string;
mod support; mod support;
mod try_catch; mod try_catch;
@ -68,6 +69,7 @@ pub use promise::{
pub use property::PropertyCallbackInfo; pub use property::PropertyCallbackInfo;
pub use script::{Script, ScriptOrigin}; pub use script::{Script, ScriptOrigin};
pub use script_or_module::ScriptOrModule; pub use script_or_module::ScriptOrModule;
pub use snapshot::{FunctionCodeHandling, SnapshotCreator, StartupData};
pub use string::NewStringType; pub use string::NewStringType;
pub use string::String; pub use string::String;
pub use try_catch::{TryCatch, TryCatchScope}; pub use try_catch::{TryCatch, TryCatchScope};

83
src/snapshot.rs Normal file
View file

@ -0,0 +1,83 @@
use crate::support::int;
use crate::Context;
use crate::Isolate;
use crate::Local;
use std::mem::MaybeUninit;
extern "C" {
fn v8__SnapshotCreator__CONSTRUCT(buf: &mut MaybeUninit<SnapshotCreator>);
fn v8__SnapshotCreator__DESTRUCT(this: &mut SnapshotCreator);
fn v8__SnapshotCreator__GetIsolate(
this: &mut SnapshotCreator,
) -> &mut Isolate;
fn v8__SnapshotCreator__CreateBlob(
this: *mut SnapshotCreator,
function_code_handling: FunctionCodeHandling,
) -> StartupData;
fn v8__SnapshotCreator__SetDefaultContext(
this: &mut SnapshotCreator,
context: *mut Context,
);
}
#[derive(Debug)]
#[repr(C)]
pub struct StartupData {
pub data: *const u8,
pub raw_size: int,
}
#[repr(C)]
pub enum FunctionCodeHandling {
Clear,
Keep,
}
/// Helper class to create a snapshot data blob.
#[repr(C)]
pub struct SnapshotCreator([usize; 1]);
impl Default for SnapshotCreator {
/// Create and enter an isolate, and set it up for serialization.
/// The isolate is created from scratch.
fn default() -> Self {
let mut snapshot_creator: MaybeUninit<Self> = MaybeUninit::uninit();
unsafe {
v8__SnapshotCreator__CONSTRUCT(&mut snapshot_creator);
snapshot_creator.assume_init()
}
}
}
impl Drop for SnapshotCreator {
fn drop(&mut self) {
unsafe { v8__SnapshotCreator__DESTRUCT(self) };
}
}
impl SnapshotCreator {
/// Set the default context to be included in the snapshot blob.
/// The snapshot will not contain the global proxy, and we expect one or a
/// global object template to create one, to be provided upon deserialization.
pub fn set_default_context<'sc>(&mut self, mut context: Local<'sc, Context>) {
unsafe { v8__SnapshotCreator__SetDefaultContext(self, &mut *context) };
}
/// Creates a snapshot data blob.
/// This must not be called from within a handle scope.
///
/// Returns { nullptr, 0 } on failure, and a startup snapshot on success.
/// The caller acquires ownership of the data array in the return value.
pub fn create_blob(
&mut self,
function_code_handling: FunctionCodeHandling,
) -> StartupData {
unsafe { v8__SnapshotCreator__CreateBlob(self, function_code_handling) }
}
/// Returns the isolate prepared by the snapshot creator.
pub fn get_isolate(&mut self) -> &Isolate {
unsafe { v8__SnapshotCreator__GetIsolate(self) }
}
}

View file

@ -1028,3 +1028,55 @@ fn array_buffer_view() {
isolate.exit(); isolate.exit();
drop(g); drop(g);
} }
#[test]
fn snapshot_creator() {
let g = setup();
// First we create the snapshot, there is a single global variable 'a' set to
// the value 3.
let mut startup_data = {
let mut snapshot_creator = v8::SnapshotCreator::default();
let isolate = snapshot_creator.get_isolate();
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
let mut context = v8::Context::new(scope);
context.enter();
let source = v8::String::new(scope, "a = 1 + 2").unwrap();
let mut script =
v8::Script::compile(scope, context, source, None).unwrap();
script.run(scope, context).unwrap();
snapshot_creator.set_default_context(context);
context.exit();
});
snapshot_creator.create_blob(v8::FunctionCodeHandling::Clear)
};
assert!(startup_data.raw_size > 0);
// Now we try to load up the snapshot and check that 'a' has the correct
// value.
{
let mut params = v8::Isolate::create_params();
params.set_array_buffer_allocator(v8::Allocator::new_default_allocator());
params.set_snapshot_blob(&mut startup_data);
let isolate = v8::Isolate::new(params);
let mut locker = v8::Locker::new(&isolate);
v8::HandleScope::enter(&mut locker, |scope| {
let mut context = v8::Context::new(scope);
context.enter();
let source = v8::String::new(scope, "a === 3").unwrap();
let mut script =
v8::Script::compile(scope, context, source, None).unwrap();
let result = script.run(scope, context).unwrap();
let true_val: Local<v8::Value> = cast(v8::new_true(scope));
assert!(result.same_value(true_val));
context.exit();
});
}
// TODO(ry) startup_data is getting leaked and is not cleaned up properly!
// It must be freed using c++ delete.
drop(g);
}