0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-11-21 05:43:13 -05:00

feat: changes for vm (#1557)

This commit is contained in:
snek 2024-08-05 02:15:56 -07:00 committed by GitHub
parent 654341e1bb
commit adf56a4f0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 462 additions and 339 deletions

View file

@ -11,7 +11,7 @@ fn main() {
v8::V8::initialize();
let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
let handle_scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(handle_scope);
let context = v8::Context::new(handle_scope, Default::default());
let scope = &mut v8::ContextScope::new(handle_scope, context);
let global = context.global(scope);
{

View file

@ -36,7 +36,7 @@ fn main() {
&mut v8::Isolate::new(v8::CreateParams::default().cpp_heap(heap));
let handle_scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(handle_scope);
let context = v8::Context::new(handle_scope, Default::default());
let scope = &mut v8::ContextScope::new(handle_scope, context);
let global = context.global(scope);
{

View file

@ -12,7 +12,7 @@ fn main() {
let handle_scope = &mut v8::HandleScope::new(isolate);
// Create a new context.
let context = v8::Context::new(handle_scope);
let context = v8::Context::new(handle_scope, Default::default());
// Enter the context for compiling and running the hello world script.
let scope = &mut v8::ContextScope::new(handle_scope, context);

View file

@ -148,7 +148,13 @@ where
v8::FunctionTemplate::new(isolate_scope, log_callback).into(),
);
let context = v8::Context::new_from_template(isolate_scope, global);
let context = v8::Context::new(
isolate_scope,
v8::ContextOptions {
global_template: Some(global),
..Default::default()
},
);
let mut context_scope = v8::ContextScope::new(isolate_scope, context);
let request_template = v8::ObjectTemplate::new(&mut context_scope);

View file

@ -12,7 +12,7 @@ fn main() {
let isolate = &mut v8::Isolate::new(v8::CreateParams::default());
let handle_scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(handle_scope);
let context = v8::Context::new(handle_scope, Default::default());
let context_scope = &mut v8::ContextScope::new(handle_scope, context);
let scope = &mut v8::HandleScope::new(context_scope);

View file

@ -345,6 +345,11 @@ void v8__Isolate__SetWasmStreamingCallback(v8::Isolate* isolate,
isolate->SetWasmStreamingCallback(callback);
}
void v8__Isolate__SetAllowWasmCodeGenerationCallback(
v8::Isolate* isolate, v8::AllowWasmCodeGenerationCallback callback) {
isolate->SetAllowWasmCodeGenerationCallback(callback);
}
bool v8__Isolate__HasPendingBackgroundTasks(v8::Isolate* isolate) {
return isolate->HasPendingBackgroundTasks();
}
@ -1651,6 +1656,13 @@ const v8::Value* v8__Object__GetRealNamedProperty(const v8::Object& self,
ptr_to_local(&context), ptr_to_local(&key)));
}
MaybeBool v8__Object__HasRealNamedProperty(const v8::Object& self,
const v8::Context& context,
const v8::Name& key) {
return maybe_to_maybe_bool(ptr_to_local(&self)->HasRealNamedProperty(
ptr_to_local(&context), ptr_to_local(&key)));
}
void v8__Object__GetRealNamedPropertyAttributes(
const v8::Object& self, const v8::Context& context, const v8::Name& key,
v8::Maybe<v8::PropertyAttribute>* out) {
@ -1943,12 +1955,13 @@ void DeserializeInternalFields(v8::Local<v8::Object> holder, int index,
const v8::Context* v8__Context__New(v8::Isolate* isolate,
const v8::ObjectTemplate* templ,
const v8::Value* global_object) {
return local_to_ptr(
v8::Context::New(isolate, nullptr, ptr_to_maybe_local(templ),
ptr_to_maybe_local(global_object),
v8::DeserializeInternalFieldsCallback(
DeserializeInternalFields, nullptr)));
const v8::Value* global_object,
v8::MicrotaskQueue* microtask_queue) {
return local_to_ptr(v8::Context::New(
isolate, nullptr, ptr_to_maybe_local(templ),
ptr_to_maybe_local(global_object),
v8::DeserializeInternalFieldsCallback(DeserializeInternalFields, nullptr),
microtask_queue));
}
bool v8__Context__EQ(const v8::Context& self, const v8::Context& other) {
@ -2035,10 +2048,13 @@ void v8__Context__SetMicrotaskQueue(v8::Context& self,
ptr_to_local(&self)->SetMicrotaskQueue(microtask_queue);
}
const v8::Context* v8__Context__FromSnapshot(v8::Isolate* isolate,
size_t context_snapshot_index) {
v8::MaybeLocal<v8::Context> maybe_local =
v8::Context::FromSnapshot(isolate, context_snapshot_index);
const v8::Context* v8__Context__FromSnapshot(
v8::Isolate* isolate, size_t context_snapshot_index,
v8::Value* global_object, v8::MicrotaskQueue* microtask_queue) {
v8::MaybeLocal<v8::Context> maybe_local = v8::Context::FromSnapshot(
isolate, context_snapshot_index,
v8::DeserializeInternalFieldsCallback(DeserializeInternalFields, nullptr),
nullptr, ptr_to_maybe_local(global_object), microtask_queue);
return maybe_local_to_ptr(maybe_local);
}

View file

@ -22,6 +22,7 @@ extern "C" {
isolate: *mut Isolate,
templ: *const ObjectTemplate,
global_object: *const Value,
microtask_queue: *mut MicrotaskQueue,
) -> *const Context;
fn v8__Context__GetIsolate(this: *const Context) -> *mut Isolate;
fn v8__Context__Global(this: *const Context) -> *const Object;
@ -40,6 +41,8 @@ extern "C" {
fn v8__Context__FromSnapshot(
isolate: *mut Isolate,
context_snapshot_index: usize,
global_object: *const Value,
microtask_queue: *mut MicrotaskQueue,
) -> *const Context;
pub(super) fn v8__Context__GetSecurityToken(
this: *const Context,
@ -65,31 +68,45 @@ extern "C" {
);
}
#[derive(Default)]
pub struct ContextOptions<'s> {
/// An optional object template from which the global object for the newly created context will
/// be created.
pub global_template: Option<Local<'s, ObjectTemplate>>,
/// An optional global object to be reused for the newly created context. This global object
/// must have been created by a previous call to Context::New with the same global template.
/// The state of the global object will be completely reset and only object identify will
/// remain.
pub global_object: Option<Local<'s, Value>>,
/// An optional microtask queue used to manage the microtasks created in this context. If not
/// set the per-isolate default microtask queue would be used.
pub microtask_queue: Option<*mut MicrotaskQueue>,
}
impl Context {
const ANNEX_SLOT: int = 1;
const INTERNAL_SLOT_COUNT: int = 1;
/// Creates a new context.
#[inline(always)]
pub fn new<'s>(scope: &mut HandleScope<'s, ()>) -> Local<'s, Context> {
// TODO: optional arguments;
unsafe {
scope
.cast_local(|sd| v8__Context__New(sd.get_isolate_ptr(), null(), null()))
}
.unwrap()
}
/// Creates a new context using the object template as the template for
/// the global object.
#[inline(always)]
pub fn new_from_template<'s>(
pub fn new<'s>(
scope: &mut HandleScope<'s, ()>,
templ: Local<ObjectTemplate>,
options: ContextOptions,
) -> Local<'s, Context> {
unsafe {
scope.cast_local(|sd| {
v8__Context__New(sd.get_isolate_ptr(), &*templ, null())
v8__Context__New(
sd.get_isolate_ptr(),
options
.global_template
.map(|t| &*t as *const _)
.unwrap_or_else(null),
options
.global_object
.map(|o| &*o as *const _)
.unwrap_or_else(null),
options.microtask_queue.unwrap_or_else(null_mut),
)
})
}
.unwrap()
@ -135,15 +152,11 @@ impl Context {
}
#[inline]
fn get_annex_mut<'a>(
&'a self,
isolate: &'a mut Isolate,
fn get_annex_mut(
&self,
create_if_not_present: bool,
) -> Option<&'a mut ContextAnnex> {
assert!(
std::ptr::eq(isolate, unsafe { v8__Context__GetIsolate(self) }),
"attempted to use Context slots with the wrong Isolate"
);
) -> Option<&mut ContextAnnex> {
let isolate = unsafe { &mut *v8__Context__GetIsolate(self) };
let num_data_fields =
unsafe { v8__Context__GetNumberOfEmbedderDataFields(self) } as int;
@ -219,11 +232,8 @@ impl Context {
/// Get a reference to embedder data added with [`Self::set_slot()`].
#[inline(always)]
pub fn get_slot<'a, T: 'static>(
&'a self,
isolate: &'a mut Isolate,
) -> Option<&'a T> {
if let Some(annex) = self.get_annex_mut(isolate, false) {
pub fn get_slot<T: 'static>(&self) -> Option<&T> {
if let Some(annex) = self.get_annex_mut(false) {
annex.slots.get(&TypeId::of::<T>()).map(|slot| {
// SAFETY: `Self::set_slot` guarantees that only values of type T will be
// stored with T's TypeId as their key.
@ -236,11 +246,8 @@ impl Context {
/// Get a mutable reference to embedder data added with [`Self::set_slot()`].
#[inline(always)]
pub fn get_slot_mut<'a, T: 'static>(
&'a self,
isolate: &'a mut Isolate,
) -> Option<&'a mut T> {
if let Some(annex) = self.get_annex_mut(isolate, false) {
pub fn get_slot_mut<T: 'static>(&self) -> Option<&mut T> {
if let Some(annex) = self.get_annex_mut(false) {
annex.slots.get_mut(&TypeId::of::<T>()).map(|slot| {
// SAFETY: `Self::set_slot` guarantees that only values of type T will be
// stored with T's TypeId as their key.
@ -263,13 +270,9 @@ impl Context {
///
/// The value will be dropped when the context is garbage collected.
#[inline(always)]
pub fn set_slot<'a, T: 'static>(
&'a self,
isolate: &'a mut Isolate,
value: T,
) -> bool {
pub fn set_slot<T: 'static>(&self, value: T) -> bool {
self
.get_annex_mut(isolate, true)
.get_annex_mut(true)
.unwrap()
.slots
.insert(TypeId::of::<T>(), RawSlot::new(value))
@ -279,11 +282,8 @@ impl Context {
/// Removes the embedder data added with [`Self::set_slot()`] and returns it
/// if it exists.
#[inline(always)]
pub fn remove_slot<'a, T: 'static>(
&'a self,
isolate: &'a mut Isolate,
) -> Option<T> {
if let Some(annex) = self.get_annex_mut(isolate, false) {
pub fn remove_slot<T: 'static>(&self) -> Option<T> {
if let Some(annex) = self.get_annex_mut(false) {
annex.slots.remove(&TypeId::of::<T>()).map(|slot| {
// SAFETY: `Self::set_slot` guarantees that only values of type T will be
// stored with T's TypeId as their key.
@ -302,8 +302,8 @@ impl Context {
/// state uses [`Weak`] handles, which cannot be alive at the time of
/// snapshotting.
#[inline(always)]
pub fn clear_all_slots<'a>(&'a self, isolate: &'a mut Isolate) {
if let Some(annex_mut) = self.get_annex_mut(isolate, false) {
pub fn clear_all_slots(&self) {
if let Some(annex_mut) = self.get_annex_mut(false) {
let annex_ptr = annex_mut as *mut ContextAnnex;
let _ = unsafe { Box::from_raw(annex_ptr) };
unsafe {
@ -323,7 +323,7 @@ impl Context {
data: *mut c_void,
) {
// Initialize the annex when slot count > INTERNAL_SLOT_COUNT.
self.get_annex_mut(&mut *v8__Context__GetIsolate(self), true);
self.get_annex_mut(true);
v8__Context__SetAlignedPointerInEmbedderData(
self,
@ -351,10 +351,19 @@ impl Context {
pub fn from_snapshot<'s>(
scope: &mut HandleScope<'s, ()>,
context_snapshot_index: usize,
options: ContextOptions,
) -> Option<Local<'s, Context>> {
unsafe {
scope.cast_local(|sd| {
v8__Context__FromSnapshot(sd.get_isolate_mut(), context_snapshot_index)
v8__Context__FromSnapshot(
sd.get_isolate_mut(),
context_snapshot_index,
options
.global_object
.map(|o| &*o as *const _)
.unwrap_or_else(null),
options.microtask_queue.unwrap_or_else(null_mut),
)
})
}
}

View file

@ -170,6 +170,9 @@ pub type WasmAsyncResolvePromiseCallback = extern "C" fn(
WasmAsyncSuccess,
);
pub type AllowWasmCodeGenerationCallback =
extern "C" fn(Local<Context>, Local<String>) -> bool;
/// HostInitializeImportMetaObjectCallback is called the first time import.meta
/// is accessed for a module. Subsequent access will reuse the same value.
///
@ -473,6 +476,10 @@ extern "C" {
isolate: *mut Isolate,
callback: WasmAsyncResolvePromiseCallback,
);
fn v8__Isolate__SetAllowWasmCodeGenerationCallback(
isolate: *mut Isolate,
callback: AllowWasmCodeGenerationCallback,
);
fn v8__Isolate__SetHostInitializeImportMetaObjectCallback(
isolate: *mut Isolate,
callback: HostInitializeImportMetaObjectCallback,
@ -1032,6 +1039,16 @@ impl Isolate {
unsafe { v8__Isolate__SetWasmAsyncResolvePromiseCallback(self, callback) }
}
#[inline(always)]
pub fn set_allow_wasm_code_generation_callback(
&mut self,
callback: AllowWasmCodeGenerationCallback,
) {
unsafe {
v8__Isolate__SetAllowWasmCodeGenerationCallback(self, callback);
}
}
#[inline(always)]
/// This specifies the callback called by the upcoming importa.meta
/// language feature to retrieve host-defined meta data for a module.

View file

@ -10,7 +10,7 @@
//! let isolate = &mut v8::Isolate::new(Default::default());
//!
//! let scope = &mut v8::HandleScope::new(isolate);
//! let context = v8::Context::new(scope);
//! let context = v8::Context::new(scope, Default::default());
//! let scope = &mut v8::ContextScope::new(scope, context);
//!
//! let code = v8::String::new(scope, "'Hello' + ' World!'").unwrap();
@ -32,6 +32,7 @@ mod array_buffer_view;
mod bigint;
mod binding;
mod context;
pub use context::ContextOptions;
pub mod cppgc;
mod data;
mod date;

View file

@ -220,6 +220,11 @@ extern "C" {
context: *const Context,
key: *const Name,
) -> *const Value;
fn v8__Object__HasRealNamedProperty(
this: *const Object,
context: *const Context,
key: *const Name,
) -> MaybeBool;
fn v8__Object__GetRealNamedPropertyAttributes(
this: *const Object,
context: *const Context,
@ -982,6 +987,22 @@ impl Object {
}
}
#[inline(always)]
pub fn has_real_named_property(
&self,
scope: &mut HandleScope,
key: Local<Name>,
) -> Option<bool> {
unsafe {
v8__Object__HasRealNamedProperty(
self,
&*scope.get_current_context(),
&*key,
)
}
.into()
}
/// Gets the property attributes of a real property which can be
/// None or any combination of ReadOnly, DontEnum and DontDelete.
/// Interceptors in the prototype chain are not called.

View file

@ -2224,6 +2224,7 @@ mod raw {
mod tests {
use super::*;
use crate::new_default_platform;
use crate::ContextOptions;
use crate::Global;
use crate::V8;
use std::any::type_name;
@ -2261,7 +2262,7 @@ mod tests {
AssertTypeOf(isolate).is::<OwnedIsolate>();
let l1_hs = &mut HandleScope::new(isolate);
AssertTypeOf(l1_hs).is::<HandleScope<()>>();
let context = Context::new(l1_hs);
let context = Context::new(l1_hs, ContextOptions::default());
{
let l2_cxs = &mut ContextScope::new(l1_hs, context);
AssertTypeOf(l2_cxs).is::<ContextScope<HandleScope>>();
@ -2437,7 +2438,7 @@ mod tests {
{
let l1_hs = &mut HandleScope::new(isolate);
AssertTypeOf(l1_hs).is::<HandleScope<()>>();
let context = Context::new(l1_hs);
let context = Context::new(l1_hs, Default::default());
global_context = Global::new(l1_hs, context);
AssertTypeOf(&HandleScope::new(l1_hs)).is::<HandleScope<()>>();
{
@ -2541,7 +2542,7 @@ mod tests {
{
let l1_cbs = &mut unsafe { CallbackScope::new(&mut *isolate) };
AssertTypeOf(l1_cbs).is::<CallbackScope<()>>();
let context = Context::new(l1_cbs);
let context = Context::new(l1_cbs, Default::default());
AssertTypeOf(&ContextScope::new(l1_cbs, context))
.is::<ContextScope<HandleScope>>();
AssertTypeOf(&HandleScope::new(l1_cbs)).is::<HandleScope<()>>();

View file

@ -196,7 +196,7 @@ impl Drop for Source {
}
#[repr(C)]
#[derive(Debug)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum CompileOptions {
NoCompileOptions = 0,
ConsumeCodeCache,
@ -232,11 +232,11 @@ pub enum NoCacheReason {
#[inline(always)]
pub fn compile_module<'s>(
scope: &mut HandleScope<'s>,
mut source: Source,
source: &mut Source,
) -> Option<Local<'s, Module>> {
compile_module2(
scope,
&mut source,
source,
CompileOptions::NoCompileOptions,
NoCacheReason::NoReason,
)
@ -284,7 +284,7 @@ pub fn compile<'s>(
#[inline(always)]
pub fn compile_function<'s>(
scope: &mut HandleScope<'s>,
mut source: Source,
source: &mut Source,
arguments: &[Local<String>],
context_extensions: &[Local<Object>],
options: CompileOptions,
@ -296,7 +296,7 @@ pub fn compile_function<'s>(
scope.cast_local(|sd| {
v8__ScriptCompiler__CompileFunction(
&*sd.get_current_context(),
&mut source,
source,
arguments.len(),
arguments.as_ptr(),
context_extensions.len(),
@ -311,7 +311,7 @@ pub fn compile_function<'s>(
#[inline(always)]
pub fn compile_unbound_script<'s>(
scope: &mut HandleScope<'s>,
mut source: Source,
source: &mut Source,
options: CompileOptions,
no_cache_reason: NoCacheReason,
) -> Option<Local<'s, UnboundScript>> {
@ -319,7 +319,7 @@ pub fn compile_unbound_script<'s>(
scope.cast_local(|sd| {
v8__ScriptCompiler__CompileUnboundScript(
sd.get_isolate_ptr(),
&mut source,
source,
options,
no_cache_reason,
)

View file

@ -3,7 +3,7 @@
pub fn main() {
let mut isolate = v8::Isolate::new(mock());
let mut scope1 = v8::HandleScope::new(&mut isolate);
let context = v8::Context::new(&mut scope1);
let context = v8::Context::new(&mut scope1, Default::default());
let mut scope2 = v8::ContextScope::new(&mut scope1, context);
let _exception = {

View file

@ -3,7 +3,7 @@
pub fn main() {
let mut isolate = v8::Isolate::new(mock());
let mut scope1 = v8::HandleScope::new(&mut isolate);
let context = v8::Context::new(&mut scope1);
let context = v8::Context::new(&mut scope1, Default::default());
let mut scope2 = v8::ContextScope::new(&mut scope1, context);
let _message = {

View file

@ -46,7 +46,7 @@ impl CoreIsolate {
// Returns false if there was an error.
fn execute(&mut self, code: &str) -> bool {
let scope = &mut v8::HandleScope::new(&mut self.0);
let context = v8::Context::new(scope);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);
let source = v8::String::new(scope, code).unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();
@ -255,17 +255,17 @@ fn context_slots() {
setup();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let context = v8::Context::new(scope, Default::default());
assert!(context.set_slot(scope, TestState(0)));
assert!(!context.set_slot(scope, TestState(1)));
assert!(context.set_slot(TestState(0)));
assert!(!context.set_slot(TestState(1)));
context.get_slot_mut::<TestState>(scope).unwrap().0 += 5;
assert_eq!(context.get_slot::<TestState>(scope).unwrap().0, 6);
context.get_slot_mut::<TestState>().unwrap().0 += 5;
assert_eq!(context.get_slot::<TestState>().unwrap().0, 6);
let value = context.remove_slot::<TestState>(scope).unwrap();
let value = context.remove_slot::<TestState>().unwrap();
assert_eq!(value.0, 6);
assert!(context.remove_slot::<TestState>(scope).is_none());
assert!(context.remove_slot::<TestState>().is_none());
}
#[test]
@ -285,9 +285,9 @@ fn dropped_context_slots() {
let dropped = Rc::new(Cell::new(false));
{
let scope = &mut v8::HandleScope::new(isolate.deref_mut());
let context = v8::Context::new(scope);
let context = v8::Context::new(scope, Default::default());
context.set_slot(scope, DropMarker(dropped.clone()));
context.set_slot(DropMarker(dropped.clone()));
}
assert!(isolate.execute("gc()"));
@ -311,9 +311,9 @@ fn dropped_context_slots_on_kept_context() {
let _global_context;
{
let scope = &mut v8::HandleScope::new(isolate.deref_mut());
let context = v8::Context::new(scope);
let context = v8::Context::new(scope, Default::default());
context.set_slot(scope, DropMarker(dropped.clone()));
context.set_slot(DropMarker(dropped.clone()));
_global_context = v8::Global::new(scope, context);
}
@ -330,12 +330,12 @@ fn clear_all_context_slots() {
{
let scope = &mut v8::HandleScope::new(&mut snapshot_creator);
let context = v8::Context::new(scope);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);
context.set_slot(scope, TestState(0));
context.clear_all_slots(scope);
assert!(context.get_slot::<TestState>(scope).is_none());
context.set_slot(TestState(0));
context.clear_all_slots();
assert!(context.get_slot::<TestState>().is_none());
scope.set_default_context(context);
}

File diff suppressed because it is too large Load diff

View file

@ -28,7 +28,7 @@ fn set_entropy_source() {
for _ in 0..N {
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);
let source = v8::String::new(scope, "Math.random()").unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();

View file

@ -10,7 +10,7 @@ fn set_flags_from_string() {
v8::V8::initialize();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);
let source = "(function() { return this })()";
let source = v8::String::new(scope, source).unwrap();

View file

@ -102,7 +102,7 @@ fn cppgc_object_wrap() {
&mut v8::Isolate::new(v8::CreateParams::default().cpp_heap(heap));
let handle_scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(handle_scope);
let context = v8::Context::new(handle_scope, Default::default());
let scope = &mut v8::ContextScope::new(handle_scope, context);
let global = context.global(scope);
{

View file

@ -9,7 +9,7 @@ fn atomics_pump_message_loop() {
v8::V8::initialize();
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);
let source = r#"
function assertEquals(a, b) {

View file

@ -9,7 +9,7 @@ fn single_threaded_default_platform() {
{
let isolate = &mut v8::Isolate::new(Default::default());
let scope = &mut v8::HandleScope::new(isolate);
let context = v8::Context::new(scope);
let context = v8::Context::new(scope, Default::default());
let scope = &mut v8::ContextScope::new(scope, context);
let source = v8::String::new(scope, "Math.random()").unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();