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 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

Make Runtime::new safe

For this, we remove the parent_rt parameter and instead always create
a "top-level runtime" for the self hosting compartment and static atoms.

To do this safely, we now call JS_Init ourselves.
  • Loading branch information
nox committed May 30, 2016
commit 066b4abb951841dd97b2c3a312818800fcb72131
@@ -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"
@@ -16,6 +16,8 @@

#[macro_use]
extern crate heapsize;
#[macro_use]
extern crate lazy_static;
extern crate libc;
#[macro_use]
extern crate log;
@@ -19,7 +19,7 @@ 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};
@@ -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());

// 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);

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);

(*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));

JS_BeginRequest(js_context);

Runtime {
rt: js_runtime,
cx: js_context,
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);

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 runtimeopts = RuntimeOptionsRef(js_runtime);
let contextopts = ContextOptionsRef(js_context);

(*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));

JS_BeginRequest(js_context);

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

@@ -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.