Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,30 @@ authors = ["David Flemström <david.flemstrom@gmail.com>"]
description = "High-level bindings to V8, the Javascript engine"
documentation = "https://dflemstr.github.io/v8-rs/v8/index.html"
homepage = "https://dflemstr.github.io/v8-rs"
keywords = ["v8", "javascript", "js", "ecmascript", "google"]
keywords = [
"v8",
"javascript",
"js",
"ecmascript",
"google",
]
license = "Apache-2.0"
name = "v8"
repository = "https://github.com/dflemstr/v8-rs"
version = "0.9.6"

[dependencies]
error-chain = "0.9.0"
lazy_static = "0.2.1"
num_cpus = "1.1.0"
error-chain = "0.11.0"
lazy_static = "1.0.0"
num_cpus = "1.8.0"
priority-queue = "0.4.5"

[dependencies.v8-sys]
path = "v8-sys"
version = "0.14.0"

[features]
shared = ["v8-sys/shared"]
unstable = []

[workspace]
members = ["v8-sys"]
1 change: 1 addition & 0 deletions rust-toolchain
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nightly
94 changes: 71 additions & 23 deletions src/allocator.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,65 @@
//! Allocators for array buffers.
use v8_sys as v8;
use v8_sys;

use std::fmt;
use std::os;
use std::mem;
use std::ptr;

/// A simple array buffer allocator that guarantees that all allocated
/// blocks are coercible to `Vec`s.
#[derive(Debug)]
pub struct Allocator(v8::ArrayBuffer_AllocatorPtr);
/// blocks are coercible to `Vec`s of `u8`.
pub struct Allocator(ptr::Shared<v8_sys::ArrayBuffer_Allocator>);

impl Allocator {
/// Creates a new allocator.
pub fn new() -> Allocator {
let raw = unsafe { v8::v8_ArrayBuffer_Allocator_Create(ALLOCATOR_FUNCTIONS) };
if raw.is_null() {
panic!("Could not create ArrayBuffer::Allocator");
}
let raw = unsafe {
ptr::Shared::new(v8_sys::impls::CreateArrayBufferAllocator(
ALLOCATOR_FUNCTIONS,
ptr::null_mut(),
))
}.expect("could not create ArrayBuffer::Allocator");

Allocator(raw)
}

/// Returns the underlying raw pointer behind this allocator.
pub fn as_raw(&self) -> v8::ArrayBuffer_AllocatorPtr {
self.0
pub fn as_ptr(&self) -> *mut v8_sys::ArrayBuffer_Allocator {
self.0.as_ptr()
}
}

impl fmt::Debug for Allocator {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Allocator({:?})", unsafe { self.0.as_ref() })
}
}

impl Drop for Allocator {
fn drop(&mut self) {
unsafe {
v8::v8_ArrayBuffer_Allocator_Destroy(self.0);
v8_sys::ArrayBuffer_Allocator_Allocator_destructor(self.0.as_ptr());
}
}
}

const ALLOCATOR_FUNCTIONS: v8::v8_AllocatorFunctions = v8::v8_AllocatorFunctions {
Allocate: Some(allocate),
AllocateUninitialized: Some(allocate_uninitialized),
Free: Some(free),
};
const ALLOCATOR_FUNCTIONS: v8_sys::impls::ArrayBufferAllocatorFunctions =
v8_sys::impls::ArrayBufferAllocatorFunctions {
Destroy: None,
Allocate: Some(allocate),
AllocateUninitialized: Some(allocate_uninitialized),
Reserve: None,
Free: Some(free),
FreeMode: Some(free_mode),
SetProtection: None,
};

extern "C" fn allocate(length: usize) -> *mut os::raw::c_void {
unsafe extern "C" fn allocate(
_this: *mut os::raw::c_void,
_fallback_fn: Option<unsafe extern "C" fn(*mut os::raw::c_void, usize) -> *mut os::raw::c_void>,
_fallback_arg: *mut os::raw::c_void,
length: usize,
) -> *mut os::raw::c_void {
let mut data = Vec::with_capacity(length);
data.resize(length, 0u8);
let ptr = data.as_mut_ptr();
Expand All @@ -49,20 +68,49 @@ extern "C" fn allocate(length: usize) -> *mut os::raw::c_void {
ptr as *mut os::raw::c_void
}

extern "C" fn allocate_uninitialized(length: usize) -> *mut os::raw::c_void {
unsafe extern "C" fn allocate_uninitialized(
_this: *mut os::raw::c_void,
_fallback_fn: Option<unsafe extern "C" fn(*mut os::raw::c_void, usize) -> *mut os::raw::c_void>,
_fallback_arg: *mut os::raw::c_void,
length: usize,
) -> *mut os::raw::c_void {
let mut data = Vec::with_capacity(length);

unsafe {
data.set_len(length);
}
data.set_len(length);

let ptr = data.as_mut_ptr();
mem::forget(data);

ptr as *mut os::raw::c_void
}

unsafe extern "C" fn free(data: *mut os::raw::c_void, length: usize) {
unsafe extern "C" fn free(
_this: *mut os::raw::c_void,
_fallback_fn: Option<unsafe extern "C" fn(*mut os::raw::c_void, *mut os::raw::c_void, usize)>,
_fallback_arg: *mut os::raw::c_void,
data: *mut os::raw::c_void,
length: usize,
) {
// TODO: restore `cap` here? Can this possibly leak memory?
drop(Vec::from_raw_parts(data, length, length));
}

unsafe extern "C" fn free_mode(
_this: *mut os::raw::c_void,
fallback_fn: Option<
unsafe extern "C" fn(*mut os::raw::c_void,
*mut os::raw::c_void,
usize,
v8_sys::ArrayBuffer_Allocator_AllocationMode),
>,
fallback_arg: *mut os::raw::c_void,
data: *mut os::raw::c_void,
length: usize,
mode: v8_sys::ArrayBuffer_Allocator_AllocationMode,
) {
if mode == v8_sys::ArrayBuffer_Allocator_AllocationMode_kNormal {
// TODO: restore `cap` here? Can this possibly leak memory?
drop(Vec::from_raw_parts(data, length, length));
} else {
fallback_fn.unwrap()(fallback_arg, data, length, mode);
}
}
66 changes: 34 additions & 32 deletions src/context.rs
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
//! Execution contexts and sandboxing.
use v8_sys as v8;
use v8_sys;
use std::ptr;
use isolate;
use util;
use handle;
use value;

/// A sandboxed execution context with its own set of built-in objects and functions.
#[derive(Debug)]
pub struct Context(isolate::Isolate, v8::ContextRef);
pub struct Context(v8_sys::Context);

/// A guard that keeps a context bound while it is in scope.
#[must_use]
pub struct ContextGuard<'a>(&'a Context);
pub struct Scope<'c>(&'c mut Context);

impl Context {
/// Creates a new context and returns a handle to the newly allocated context.
pub fn new(isolate: &isolate::Isolate) -> Context {
pub fn new<'i, 's>(
scope: &'s handle::Scope,
isolate: &'i isolate::Isolate,
) -> handle::Local<'i, 's, Context> {
unsafe {
Context(isolate.clone(),
util::invoke(isolate, |c| v8::v8_Context_New(c)).unwrap())
handle::Local::new(v8_sys::Context::New(
isolate.as_ptr(),
ptr::null_mut(),
handle::MaybeLocal::empty().into_raw(),
handle::MaybeLocal::empty().into_raw(),
v8_sys::DeserializeInternalFieldsCallback {
callback: None,
data: ptr::null_mut(),
},
))
}
}

/// Binds the context to the current scope.
///
/// Within this scope, functionality that relies on implicit contexts will work.
pub fn make_current(&self) -> ContextGuard {
self.enter();
ContextGuard(self)
}

fn enter(&self) {
unsafe { util::invoke(&self.0, |c| v8::v8_Context_Enter(c, self.1)).unwrap() }
}

fn exit(&self) {
unsafe { util::invoke(&self.0, |c| v8::v8_Context_Exit(c, self.1)).unwrap() }
pub fn scope(&mut self) -> Scope {
unsafe {
self.0.Enter();
}
Scope(self)
}

/// Returns the global proxy object.
Expand All @@ -46,29 +52,25 @@ impl Context {
/// Please note that changes to global proxy object prototype most probably would break VM---v8
/// expects only global object as a prototype of global proxy object.
///
pub fn global(&self) -> value::Object {
pub fn global(&self) -> handle::Local<value::Object> {
unsafe {
value::Object::from_raw(&self.0,
util::invoke(&self.0, |c| v8::v8_Context_Global(c, self.1))
.unwrap())
handle::Local::new(self.0.Global())
}
}
}

/// Creates a context from a set of raw pointers.
pub unsafe fn from_raw(isolate: &isolate::Isolate, raw: v8::ContextRef) -> Context {
Context(isolate.clone(), raw)
impl<'c> Scope<'c> {
pub fn context(&self) -> &Context {
&self.0
}

/// Returns the underlying raw pointer behind this context.
pub fn as_raw(&self) -> v8::ContextRef {
self.1
pub fn context_mut(&mut self) -> &mut Context {
&mut self.0
}
}

reference!(Context, v8::v8_Context_CloneRef, v8::v8_Context_DestroyRef);

impl<'a> Drop for ContextGuard<'a> {
impl<'c> Drop for Scope<'c> {
fn drop(&mut self) {
self.0.exit()
unsafe { (self.0).0.Exit() }
}
}
Loading