mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-12-26 09:13:46 -05:00
first pass at snapshots (#122)
Creating a snapshot leaks memory. We will address this in future work.
This commit is contained in:
parent
b21b67d5ae
commit
1507a897de
5 changed files with 195 additions and 2 deletions
|
@ -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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
83
src/snapshot.rs
Normal 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) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue