Skip to content

Commit

Permalink
Getting josephine to work with fitzgen's smup-smup-smup branch of mozjs
Browse files Browse the repository at this point in the history
  • Loading branch information
Alan Jeffrey committed Dec 21, 2017
1 parent 074d398 commit 41a46eb
Show file tree
Hide file tree
Showing 11 changed files with 176 additions and 77 deletions.
39 changes: 31 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,43 @@ rust:

cache: cargo

env:
- CARGO_FLAGS=""
- CARGO_FLAGS="--release"
- CARGO_FLAGS="--features debugmozjs"
- CARGO_FLAGS="--features debugmozjs --release"

before_install:
# Make sure there's only one josephine crate in the deps directory,
# which is needed for the rustdoc script.
- rm -rf target/debug/deps/*josephine*

addons:
apt:
sources:
# Provides newer gcc.
- ubuntu-toolchain-r-test
packages:
- autoconf2.13
- gcc-5
- g++-5

env:
global:
- CC="gcc-5"
- CXX="g++-5"
# Where to fetch the smup version of mozjs from
- SMUP_GIT="https://github.com/fitzgen/mozjs"
- SMUP_BRANCH="smup-smup-smup"
matrix:
- CARGO_FLAGS=""
- CARGO_FLAGS="--release"
- CARGO_FLAGS="--features debugmozjs"
- CARGO_FLAGS="--features debugmozjs --release"
- CARGO_FLAGS="--features smup" SMUP=true
- CARGO_FLAGS="--features smup --release" SMUP=true

script:
# If we're doing a smup, patch in the smup repo
- if [ $SMUP ]; then echo -e "\n[patch.crates-io]\nmozjs = { git = \"$SMUP_GIT\", branch = \"$SMUP_BRANCH\" }" >> Cargo.toml; fi
- cat Cargo.toml
- cargo build $CARGO_FLAGS -vv
- cargo test $CARGO_FLAGS
- cargo run $CARGO_FLAGS --example minidom
- cargo test --doc $CARGO_FLAGS
# The minidom example currently doesn't work with the smup
- if [ ! $SMUP ]; then cargo run $CARGO_FLAGS --example minidom; fi
- cargo run $CARGO_FLAGS --example dbllist
- if [ -z "$CARGO_FLAGS" ]; then rustdoc -L target/debug/deps/ --test README.md; fi
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "josephine"
version = "0.1.1"
version = "0.2.0"
authors = ["[email protected]"]
license = "MPL-2.0"
description = "Josephine: using JavaScript to safely manage the lifetimes of Rust data"
Expand All @@ -10,12 +10,13 @@ repository = "https://github.com/asajeffrey/josephine/"

[features]
debugmozjs = ["mozjs/debugmozjs"]
smup = []

[dependencies]
josephine_derive = "0.1.0"
mozjs = "0.1.7"
libc = "0.2.30"
log = "0.3"
mozjs = "<0.3" # Requires the smup feature for mozjs 0.2.*

[dev-dependencies]
env_logger = "0.4"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ use ::josephine::JSContext;
pub fn main() {
// Create a new JavaScript context.
// All interaction with JavaScript takes place in a context.
let ref mut cx = JSContext::new();
let ref mut cx = JSContext::new().expect("Failed to initialize JS");

// Create a new compartment in that context.
// All memory managed by JavaScript is divided into compartments,
Expand Down
2 changes: 1 addition & 1 deletion examples/dbllist/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use josephine::JSContext;

fn main() {
// Create a new JS context
let ref mut cx = JSContext::new();
let ref mut cx = JSContext::new().expect("Creating a JSContext failed");

// Create a new doubly-linked list in its own compartment
let ref mut cx = DoublyLinkedList::init(cx.create_compartment());
Expand Down
2 changes: 1 addition & 1 deletion examples/minidom/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fn main() {
let _ = env_logger::init();

debug!("Creating JSContext.");
let ref mut cx = JSContext::new();
let ref mut cx = JSContext::new().expect("Failed to build JSContext");

debug!("Creating global.");
let ref mut root = cx.new_root();
Expand Down
77 changes: 50 additions & 27 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,42 +14,42 @@ use super::ffi::JSEvaluateErr;
use super::ffi::JSInitializer;
use super::managed::JSManageable;
use super::root::trace_thread_local_roots;
use super::runtime::OwnedJSRuntime;

use js::glue::NewCompileOptions;

use js::jsapi;
use js::jsapi::Evaluate2;
use js::jsapi::Handle;
use js::jsapi::Heap;
use js::jsapi::JS::Evaluate2;
use js::jsapi::JS::Handle;
use js::heap::Heap;
use js::jsapi::JSAutoCompartment;
use js::jsapi::JSObject;
use js::jsapi::JS_AddExtraGCRootsTracer;
use js::jsapi::JS_ClearPendingException;
use js::jsapi::JS_DefineFunctions;
use js::jsapi::JS_DefineProperties;
use js::jsapi::JS_GC;
use js::jsapi::JS_GetContext;
use js::jsapi::JS_GetPendingException;
use js::jsapi::JS_GetReservedSlot;
use js::jsapi::JS_GetRuntime;
use js::jsapi::JS_IsExceptionPending;
use js::jsapi::JS_NewGlobalObject;
use js::jsapi::JS_SetReservedSlot;
use js::jsapi::MutableHandle;
use js::jsapi::JS::MutableHandle;
use js::jsapi::JS::Value;

use js::jsval::JSVal;
use js::jsval::PrivateValue;
use js::jsval::UndefinedValue;

use js::rust::Runtime;

use libc;

use std::any::TypeId;
use std::cell::RefCell;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use std::rc::Rc;
use std::str;

/// The type for JS contexts whose current state is `S`.
Expand All @@ -58,7 +58,7 @@ pub struct JSContext<S> {
global_js_object: *mut Heap<*mut JSObject>,
global_raw: *mut (),
auto_compartment: Option<JSAutoCompartment>,
runtime: Option<Rc<OwnedJSRuntime>>,
runtime: Option<Runtime>,
marker: PhantomData<S>,
}

Expand Down Expand Up @@ -122,21 +122,28 @@ impl<'a, C, T> IsInitialized<'a, C, T> for Initialized<'a, C, T> {}
pub trait IsEntered<'a, C, T> {}
impl<'a, C, T, S> IsEntered<'a, C, T> for Entered<'a, C, T, S> {}

#[cfg(feature = "smup")]
thread_local!{ static RUNTIME: RefCell<Result<Runtime,()>> = RefCell::new(Runtime::new(true)) }
#[cfg(not(feature = "smup"))]
thread_local!{ static RUNTIME: RefCell<Result<Runtime,()>> = RefCell::new(Runtime::new()) }

impl JSContext<Owned> {
/// Create a new JSContext.
pub fn new() -> JSContext<Owned> {
// TODO: set options on the runtime?
let runtime = OwnedJSRuntime::new();
let jsapi_context = unsafe { JS_GetContext(runtime.rt()) };
pub fn new() -> Result<JSContext<Owned>,()> {
let runtime = RUNTIME.with(|runtime| runtime.replace(Err(())))?;
let jsapi_context = runtime.cx();
#[cfg(feature = "smup")]
unsafe { JS_AddExtraGCRootsTracer(jsapi_context, Some(trace_thread_local_roots), ptr::null_mut()); }
#[cfg(not(feature = "smup"))]
unsafe { JS_AddExtraGCRootsTracer(runtime.rt(), Some(trace_thread_local_roots), ptr::null_mut()); }
JSContext {
Ok(JSContext {
jsapi_context: jsapi_context,
global_js_object: ptr::null_mut(),
global_raw: ptr::null_mut(),
auto_compartment: None,
runtime: Some(Rc::new(runtime)),
runtime: Some(runtime),
marker: PhantomData,
}
})
}
}

Expand All @@ -162,7 +169,8 @@ impl<S> JSContext<S> {
C: Compartment,
{
debug!("Entering compartment.");
let ac = JSAutoCompartment::new(self.jsapi_context, managed.to_jsobject());
#[allow(unused_unsafe)]
let ac = unsafe { JSAutoCompartment::new(self.jsapi_context, managed.to_jsobject()) };
JSContext {
jsapi_context: self.jsapi_context,
global_js_object: managed.to_heap_object(),
Expand All @@ -178,7 +186,8 @@ impl<S> JSContext<S> {
T: JSLifetime<'a>,
{
debug!("Entering compartment.");
let ac = JSAutoCompartment::new(self.jsapi_context, managed.to_jsobject());
#[allow(unused_unsafe)]
let ac = unsafe { JSAutoCompartment::new(self.jsapi_context, managed.to_jsobject()) };
JSContext {
jsapi_context: self.jsapi_context,
global_js_object: managed.to_heap_object(),
Expand Down Expand Up @@ -249,16 +258,27 @@ impl<S> JSContext<S> {

// TODO: can we be sure that this won't trigger GC? Or do we need to root the boxed object?
debug!("Entering compartment.");
let ac = JSAutoCompartment::new(self.jsapi_context, boxed_jsobject.get());

// Save a pointer to the native value in a private slot
unsafe { JS_SetReservedSlot(boxed_jsobject.get(), 0, PrivateValue(fat_value[0])) };
unsafe { JS_SetReservedSlot(boxed_jsobject.get(), 1, PrivateValue(fat_value[1])) };
#[allow(unused_unsafe)]
let ac = unsafe { JSAutoCompartment::new(self.jsapi_context, boxed_jsobject.get()) };

// Keep a hash map of all the class prototypes
// TODO: Fix this space leak!
let prototypes: Box<HashMap<TypeId, Box<Heap<*mut JSObject>>>> = Box::new(HashMap::new());
unsafe { JS_SetReservedSlot(boxed_jsobject.get(), 2, PrivateValue(Box::into_raw(prototypes) as *const _)) };

// Save a pointer to the native value in a private slot
#[cfg(feature = "smup")]
unsafe {
JS_SetReservedSlot(boxed_jsobject.get(), 0, &PrivateValue(fat_value[0]));
JS_SetReservedSlot(boxed_jsobject.get(), 1, &PrivateValue(fat_value[1]));
// TODO: Fix this space leak!
JS_SetReservedSlot(boxed_jsobject.get(), 2, &PrivateValue(Box::into_raw(prototypes) as *const _));
}
#[cfg(not(feature = "smup"))]
unsafe {
JS_SetReservedSlot(boxed_jsobject.get(), 0, PrivateValue(fat_value[0]));
JS_SetReservedSlot(boxed_jsobject.get(), 1, PrivateValue(fat_value[1]));
// TODO: Fix this space leak!
JS_SetReservedSlot(boxed_jsobject.get(), 2, PrivateValue(Box::into_raw(prototypes) as *const _));
}

// Define the properties and functions of the global
if !properties.is_null() { unsafe { JS_DefineProperties(self.jsapi_context, boxed_jsobject.handle(), properties) }; }
Expand All @@ -274,7 +294,7 @@ impl<S> JSContext<S> {
global_js_object: Box::into_raw(boxed_jsobject),
global_raw: fat_value[0] as *mut (),
auto_compartment: Some(ac),
runtime: self.runtime.clone(),
runtime: None,
marker: PhantomData,
}
}
Expand Down Expand Up @@ -330,6 +350,9 @@ impl<S> JSContext<S> {
pub fn gc(&mut self) where
S: CanAlloc,
{
#[cfg(feature = "smup")]
unsafe { JS_GC(self.cx()); }
#[cfg(not(feature = "smup"))]
unsafe { JS_GC(self.rt()); }
}

Expand All @@ -345,7 +368,7 @@ impl<S> JSContext<S> {
}).handle()
}

pub fn evaluate<C>(&mut self, code: &str) -> Result<JSVal, JSEvaluateErr> where
pub fn evaluate<C>(&mut self, code: &str) -> Result<Value, JSEvaluateErr> where
S: InCompartment<C>,
{
let cx = self.jsapi_context;
Expand Down
39 changes: 29 additions & 10 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ pub use super::managed::jsmanaged_called_from_js;
pub use super::string::jsstring_called_from_js;

use js::jsapi;
use js::jsapi::CompartmentOptions;
use js::jsapi::Handle;
use js::jsapi::JS::CompartmentOptions;
use js::jsapi::JS::Handle;
use js::jsapi::JS::HandleObject;
use js::jsapi::JSCLASS_RESERVED_SLOTS_SHIFT;
use js::jsapi::JSClass;
use js::jsapi::JSClassOps;
Expand All @@ -31,11 +32,11 @@ use js::jsapi::JS_GlobalObjectTraceHook;
use js::jsapi::JS_InitClass;
use js::jsapi::JS_InitStandardClasses;
use js::jsapi::JS_IsNative;
use js::jsapi::OnNewGlobalHookOption;
use js::jsapi::JS::OnNewGlobalHookOption;

use js::JSCLASS_GLOBAL_SLOT_COUNT;
use js::JSCLASS_IS_GLOBAL;
use js::JSCLASS_RESERVED_SLOTS_MASK;
use js::jsapi::JSCLASS_GLOBAL_SLOT_COUNT;
use js::jsapi::JSCLASS_IS_GLOBAL;
use js::jsapi::JSCLASS_RESERVED_SLOTS_MASK;

use libc::c_char;
use libc::c_uint;
Expand Down Expand Up @@ -73,7 +74,7 @@ impl JSInitializable for usize {}
/// Initialize JS data
pub trait JSInitializer {
unsafe fn parent_prototype(cx: *mut jsapi::JSContext, global: jsapi::HandleObject) -> *mut JSObject {
unsafe fn parent_prototype(cx: *mut jsapi::JSContext, global: HandleObject) -> *mut JSObject {
JS_GetObjectPrototype(cx, global)
}

Expand Down Expand Up @@ -125,7 +126,7 @@ pub trait JSInitializer {
ptr::null()
}

unsafe fn js_init_class(cx: *mut jsapi::JSContext, global: jsapi::HandleObject) -> *mut JSObject {
unsafe fn js_init_class(cx: *mut jsapi::JSContext, global: HandleObject) -> *mut JSObject {
let ref parent_proto = Self::parent_prototype(cx, global);
let parent_proto_handle = Handle::from_marked_location(parent_proto);
let classp = Self::classp();
Expand All @@ -137,10 +138,10 @@ pub trait JSInitializer {
JS_InitClass(cx, global, parent_proto_handle, classp, constructor, nargs, ps, fs, static_ps, static_fs)
}

unsafe fn js_init_object(_cx: *mut jsapi::JSContext, _obj: jsapi::HandleObject) {
unsafe fn js_init_object(_cx: *mut jsapi::JSContext, _obj: HandleObject) {
}

unsafe fn js_init_global(cx: *mut jsapi::JSContext, global: jsapi::HandleObject) {
unsafe fn js_init_global(cx: *mut jsapi::JSContext, global: HandleObject) {
JS_InitStandardClasses(cx, global);
}
}
Expand All @@ -160,11 +161,15 @@ static DEFAULT_CLASS: JSClass = JSClass {
construct: None,
delProperty: None,
enumerate: None,
#[cfg(feature = "smup")]
newEnumerate: None,
finalize: Some(finalize_jsobject_with_native_data),
#[cfg(not(feature = "smup"))]
getProperty: None,
hasInstance: None,
mayResolve: None,
resolve: None,
#[cfg(not(feature = "smup"))]
setProperty: None,
trace: Some(trace_jsobject_with_native_data),
},
Expand All @@ -180,11 +185,15 @@ static DEFAULT_GLOBAL_CLASS: JSClass = JSClass {
construct: None,
delProperty: None,
enumerate: None,
#[cfg(feature = "smup")]
newEnumerate: None,
finalize: Some(finalize_jsobject_with_native_data),
#[cfg(not(feature = "smup"))]
getProperty: None,
hasInstance: None,
mayResolve: None,
resolve: None,
#[cfg(not(feature = "smup"))]
setProperty: None,
trace: Some(JS_GlobalObjectTraceHook),
},
Expand All @@ -198,6 +207,11 @@ pub const fn null_wrapper() -> JSNativeWrapper {
}
}

#[cfg(feature = "smup")]
pub const fn null_property() -> JSPropertySpec {
JSPropertySpec::NULL
}
#[cfg(not(feature = "smup"))]
pub const fn null_property() -> JSPropertySpec {
JSPropertySpec {
name: ptr::null(),
Expand All @@ -207,6 +221,11 @@ pub const fn null_property() -> JSPropertySpec {
}
}

#[cfg(feature = "smup")]
pub const fn null_function() -> JSFunctionSpec {
JSFunctionSpec::NULL
}
#[cfg(not(feature = "smup"))]
pub const fn null_function() -> JSFunctionSpec {
JSFunctionSpec {
name: ptr::null(),
Expand Down
Loading

0 comments on commit 41a46eb

Please sign in to comment.