Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Runtime::new safe #267

Merged
merged 2 commits into from May 30, 2016
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -25,6 +25,7 @@ debugmozjs = ['mozjs_sys/debugmozjs']
git = "https://github.com/servo/mozjs"

[dependencies]
lazy_static = "0.2.1"
libc = "0.2"
rustc-serialize = "0.3"
log = "0.3"
@@ -39,7 +39,7 @@ use jsval::{BooleanValue, Int32Value, NullValue, UInt32Value, UndefinedValue};
use jsval::{JSVal, ObjectValue, ObjectOrNullValue, StringValue};
use rust::{ToBoolean, ToNumber, ToUint16, ToInt32, ToUint32, ToInt64, ToUint64, ToString};
use libc;
use num_traits::{Bounded, Float, Zero};
use num_traits::{Bounded, Zero};
use std::rc::Rc;
use std::{ptr, slice};

@@ -3,7 +3,7 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */


use jsapi::{__BindgenUnionField, JSObject, JSString, TraceKind};
use jsapi::{JSObject, JSString, TraceKind};
use jsapi::Value;
use jsapi::jsval_layout;
use jsapi::JSValueType;
@@ -16,6 +16,8 @@

#[macro_use]
extern crate heapsize;
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate log;
@@ -19,15 +19,15 @@ use std::cell::UnsafeCell;
use std::marker::PhantomData;
use consts::{JSCLASS_RESERVED_SLOTS_MASK, JSCLASS_GLOBAL_SLOT_COUNT, JSCLASS_IS_GLOBAL};
use jsapi;
use jsapi::{JS_NewContext, JS_DestroyContext, JS_NewRuntime, JS_DestroyRuntime};
use jsapi::{JS_Init, JS_NewContext, JS_DestroyContext, JS_NewRuntime, JS_DestroyRuntime};
use jsapi::{JSContext, JSRuntime, JSObject, JSFlatString, JSFunction, JSString, Symbol, JSScript, jsid, Value};
use jsapi::{RuntimeOptionsRef, ContextOptionsRef, ReadOnlyCompileOptions};
use jsapi::{JS_SetErrorReporter, Evaluate2, JSErrorReport};
use jsapi::{JS_SetGCParameter, JSGCParamKey};
use jsapi::{JSWhyMagic, Heap, Cell, HeapObjectPostBarrier, HeapValuePostBarrier};
use jsapi::{Heap, HeapObjectPostBarrier, HeapValuePostBarrier};
use jsapi::{ContextFriendFields};
use jsapi::{CustomAutoRooter, AutoGCRooter, _vftable_CustomAutoRooter, AutoGCRooter_jspubtd_h_unnamed_1};
use jsapi::{Rooted, RootedValue, Handle, MutableHandle, MutableHandleBase, RootedBase};
use jsapi::{Rooted, Handle, MutableHandle, MutableHandleBase, RootedBase};
use jsapi::{MutableHandleValue, HandleValue, HandleObject, HandleBase};
use jsapi::AutoObjectVector;
use jsapi::{ToBooleanSlow, ToNumberSlow, ToStringSlow};
@@ -112,46 +112,64 @@ pub struct Runtime {

impl Runtime {
/// Creates a new `JSRuntime` and `JSContext`.
///
/// # Safety
///
/// Calling this function concurrently can cause segfaults inside
/// SpiderMonkey
pub unsafe fn new(parent_rt: *mut JSRuntime) -> Runtime {
let js_runtime = JS_NewRuntime(default_heapsize, ChunkSize as u32, parent_rt);
assert!(!js_runtime.is_null());
pub fn new() -> Runtime {
unsafe {
struct TopRuntime(*mut JSRuntime);
unsafe impl Sync for TopRuntime {}

lazy_static! {
static ref PARENT: TopRuntime = {
unsafe {
assert!(JS_Init());
let runtime = JS_NewRuntime(
default_heapsize, ChunkSize as u32, ptr::null_mut());
assert!(!runtime.is_null());
let context = JS_NewContext(
runtime, default_stacksize as size_t);
assert!(!context.is_null());
TopRuntime(runtime)
}
};
}

let js_runtime =
JS_NewRuntime(default_heapsize, ChunkSize as u32, PARENT.0);
assert!(!js_runtime.is_null());

// Unconstrain the runtime's threshold on nominal heap size, to avoid
// triggering GC too often if operating continuously near an arbitrary
// finite threshold. This leaves the maximum-JS_malloc-bytes threshold
// still in effect to cause periodical, and we hope hygienic,
// last-ditch GCs from within the GC's allocator.
JS_SetGCParameter(js_runtime, JSGCParamKey::JSGC_MAX_BYTES, u32::MAX);
// Unconstrain the runtime's threshold on nominal heap size, to avoid
// triggering GC too often if operating continuously near an arbitrary
// finite threshold. This leaves the maximum-JS_malloc-bytes threshold
// still in effect to cause periodical, and we hope hygienic,
// last-ditch GCs from within the GC's allocator.
JS_SetGCParameter(
js_runtime, JSGCParamKey::JSGC_MAX_BYTES, u32::MAX);

JS_SetNativeStackQuota(js_runtime,
STACK_QUOTA,
STACK_QUOTA - SYSTEM_CODE_BUFFER,
STACK_QUOTA - SYSTEM_CODE_BUFFER - TRUSTED_SCRIPT_BUFFER);
JS_SetNativeStackQuota(
js_runtime,
STACK_QUOTA,
STACK_QUOTA - SYSTEM_CODE_BUFFER,
STACK_QUOTA - SYSTEM_CODE_BUFFER - TRUSTED_SCRIPT_BUFFER);

let js_context = JS_NewContext(js_runtime, default_stacksize as size_t);
assert!(!js_context.is_null());
let js_context = JS_NewContext(js_runtime, default_stacksize as size_t);
assert!(!js_context.is_null());

let runtimeopts = RuntimeOptionsRef(js_runtime);
let contextopts = ContextOptionsRef(js_context);
let runtimeopts = RuntimeOptionsRef(js_runtime);
let contextopts = ContextOptionsRef(js_context);

(*runtimeopts).set_baseline_(true);
(*runtimeopts).set_ion_(true);
(*runtimeopts).set_nativeRegExp_(true);
(*runtimeopts).set_baseline_(true);
(*runtimeopts).set_ion_(true);
(*runtimeopts).set_nativeRegExp_(true);

(*contextopts).set_dontReportUncaught_(true);
(*contextopts).set_autoJSAPIOwnsErrorReporting_(true);
JS_SetErrorReporter(js_runtime, Some(reportError));
(*contextopts).set_dontReportUncaught_(true);
(*contextopts).set_autoJSAPIOwnsErrorReporting_(true);
JS_SetErrorReporter(js_runtime, Some(reportError));

JS_BeginRequest(js_context);
JS_BeginRequest(js_context);

Runtime {
rt: js_runtime,
cx: js_context,
Runtime {
rt: js_runtime,
cx: js_context,
}
}
}

@@ -438,30 +456,10 @@ impl Default for CompartmentOptions {

const ChunkShift: usize = 20;
const ChunkSize: usize = 1 << ChunkShift;
const ChunkMask: usize = ChunkSize - 1;

#[cfg(target_pointer_width = "32")]
const ChunkLocationOffset: usize = ChunkSize - 2 * 4 - 8;

#[cfg(target_pointer_width = "64")]
const ChunkLocationOffset: usize = ChunkSize - 2 * 8 - 8;

const ChunkLocationBitNursery: usize = 1;

fn IsInsideNursery(p: *mut Cell) -> bool {
if p.is_null() {
return false;
}

let mut addr: usize = unsafe { mem::transmute(p) };
addr = (addr & !ChunkMask) | ChunkLocationOffset;

let location: *const u32 = unsafe { mem::transmute(addr) };
let location = unsafe { *location };
assert!(location != 0);
(location & ChunkLocationBitNursery as u32) != 0
}

pub trait GCMethods<T> {
unsafe fn initial() -> T;
unsafe fn is_dropped(self) -> bool;
@@ -11,7 +11,6 @@ use js::jsapi::JSAutoCompartment;
use js::jsapi::JSContext;
use js::jsapi::JS_DefineFunction;
use js::jsapi::JS_EncodeStringToUTF8;
use js::jsapi::JS_Init;
use js::jsapi::JS_NewGlobalObject;
use js::jsapi::JS_ReportError;
use js::jsapi::OnNewGlobalHookOption;
@@ -27,14 +26,12 @@ use std::str;

#[test]
fn callback() {
unsafe {
JS_Init();

let runtime = Runtime::new(ptr::null_mut());
let context = runtime.cx();
let runtime = Runtime::new();
let context = runtime.cx();
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
let c_option = CompartmentOptions::default();

let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
let c_option = CompartmentOptions::default();
unsafe {
let global = JS_NewGlobalObject(context, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(), h_option, &c_option);
let global_root = Rooted::new(context, global);
let global = global_root.handle();
@@ -5,7 +5,6 @@
extern crate js;

use js::jsapi::CompartmentOptions;
use js::jsapi::JS_Init;
use js::jsapi::JS_NewGlobalObject;
use js::jsapi::OnNewGlobalHookOption;
use js::jsapi::RootedObject;
@@ -17,10 +16,10 @@ use std::ptr;

#[test]
fn evaluate() {
let rt = Runtime::new();
let cx = rt.cx();

unsafe {
assert!(JS_Init());
let rt = Runtime::new(ptr::null_mut());
let cx = rt.cx();

let global = RootedObject::new(cx,
JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS, ptr::null_mut(),
@@ -5,7 +5,6 @@
extern crate js;

use js::jsapi::CompartmentOptions;
use js::jsapi::JS_Init;
use js::jsapi::JS_NewGlobalObject;
use js::jsapi::OnNewGlobalHookOption;
use js::jsapi::Rooted;
@@ -17,12 +16,10 @@ use std::ptr;

#[test]
fn stack_limit() {
unsafe {
assert!(JS_Init());

let rt = Runtime::new(ptr::null_mut());
let cx = rt.cx();
let rt = Runtime::new();
let cx = rt.cx();

unsafe {
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
let c_option = CompartmentOptions::default();
let global = JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS,
@@ -9,7 +9,6 @@ use js::conversions::FromJSValConvertible;
use js::conversions::ToJSValConvertible;
use js::jsapi::CompartmentOptions;
use js::jsapi::JSAutoCompartment;
use js::jsapi::JS_Init;
use js::jsapi::JS_InitStandardClasses;
use js::jsapi::JS_NewGlobalObject;
use js::jsapi::OnNewGlobalHookOption;
@@ -22,14 +21,13 @@ use std::ptr;

#[test]
fn vec_conversion() {
unsafe {
assert!(JS_Init());
let rt = Runtime::new();
let cx = rt.cx();

let rt = Runtime::new(ptr::null_mut());
let cx = rt.cx();
let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
let c_option = CompartmentOptions::default();

let h_option = OnNewGlobalHookOption::FireOnNewGlobalHook;
let c_option = CompartmentOptions::default();
unsafe {
let global = JS_NewGlobalObject(cx, &SIMPLE_GLOBAL_CLASS,
ptr::null_mut(), h_option, &c_option);
let global_root = Rooted::new(cx, global);
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.