Make GC work.

This commit is contained in:
Josh Matthews 2013-04-10 10:37:49 -04:00
parent 535bfb3cbb
commit db5eca4764
10 changed files with 128 additions and 42 deletions

7
src/patches/README Normal file
View file

@ -0,0 +1,7 @@
Patches live here for submodules that should remain as pristine as possible.
This will allow us to unconditionally update them, then apply necessary
patches as needed.
* mozjs-stack-bounds.diff:
add a public API to overwrite the engine's computed stack bounds for
GC scanning.

View file

@ -0,0 +1,72 @@
diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp
index 5571fc0..df2fabd 100644
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -735,6 +735,7 @@ JSRuntime::JSRuntime()
#endif
selfHostedGlobal_(NULL),
nativeStackBase(0),
+ nativeStackEnd(0),
nativeStackQuota(0),
interpreterFrames(NULL),
cxCallback(NULL),
@@ -7084,6 +7085,13 @@ JS_SetRuntimeThread(JSRuntime *rt)
#endif
}
+extern JS_PUBLIC_API(void)
+JS_SetNativeStackBounds(JSRuntime *rt, uintptr_t stackBase, uintptr_t stackEnd)
+{
+ rt->nativeStackBase = stackBase;
+ rt->nativeStackEnd = stackEnd;
+}
+
extern JS_NEVER_INLINE JS_PUBLIC_API(void)
JS_AbortIfWrongThread(JSRuntime *rt)
{
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index c8ab0f0..0edb722 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -6248,6 +6248,9 @@ JS_ClearRuntimeThread(JSRuntime *rt);
extern JS_PUBLIC_API(void)
JS_SetRuntimeThread(JSRuntime *rt);
+extern JS_PUBLIC_API(void)
+JS_SetNativeStackBounds(JSRuntime *rt, uintptr_t stackBase, uintptr_t stackEnd);
+
#ifdef __cplusplus
JS_END_EXTERN_C
diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h
index 0bb6d1c..32e016e 100644
--- a/js/src/jscntxt.h
+++ b/js/src/jscntxt.h
@@ -439,6 +439,9 @@ struct JSRuntime : js::RuntimeFriendFields
/* Base address of the native stack for the current thread. */
uintptr_t nativeStackBase;
+ /* Base address of the native stack for the current thread. */
+ uintptr_t nativeStackEnd;
+
/* The native stack size limit that runtime should not exceed. */
size_t nativeStackQuota;
diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp
index f5cbc62..eae29da 100644
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -1177,9 +1177,11 @@ MarkConservativeStackRoots(JSTracer *trc, bool useSavedRoots)
uintptr_t *stackMin, *stackEnd;
#if JS_STACK_GROWTH_DIRECTION > 0
stackMin = rt->nativeStackBase;
- stackEnd = cgcd->nativeStackTop;
+ stackEnd = rt->nativeStackEnd ? reinterpret_cast<uintptr_t*>(rt->nativeStackEnd)
+ : cgcd->nativeStackTop;
#else
- stackMin = cgcd->nativeStackTop + 1;
+ stackMin = rt->nativeStackEnd ? reinterpret_cast<uintptr_t*>(rt->nativeStackEnd)
+ : cgcd->nativeStackTop + 1;
stackEnd = reinterpret_cast<uintptr_t *>(rt->nativeStackBase);
#endif

View file

@ -32,10 +32,10 @@ extern fn finalize(_fop: *JSFreeOp, obj: *JSObject) {
} }
} }
pub extern fn trace(tracer: *JSTracer, obj: *JSObject) { pub extern fn trace(tracer: *mut JSTracer, obj: *JSObject) {
let node = unsafe { unwrap(obj) }; let node = unsafe { unwrap(obj) };
fn trace_node(tracer: *JSTracer, node: Option<AbstractNode>, name: &str) { fn trace_node(tracer: *mut JSTracer, node: Option<AbstractNode>, name: &str) {
if node.is_none() { if node.is_none() {
return; return;
} }
@ -45,7 +45,12 @@ pub extern fn trace(tracer: *JSTracer, obj: *JSObject) {
let wrapper = cache.get_wrapper(); let wrapper = cache.get_wrapper();
assert!(wrapper.is_not_null()); assert!(wrapper.is_not_null());
unsafe { unsafe {
JS_CallTracer(tracer, wrapper, JSTRACE_OBJECT as u32); (*tracer).debugPrinter = ptr::null();
(*tracer).debugPrintIndex = -1;
do str::as_c_str(name) |name| {
(*tracer).debugPrintArg = name as *libc::c_void;
JS_CallTracer(cast::transmute(tracer), wrapper, JSTRACE_OBJECT as u32);
}
} }
} }
error!("tracing %?:", obj as uint); error!("tracing %?:", obj as uint);

View file

@ -290,10 +290,8 @@ static DOM_PROXY_OBJECT_SLOT: uint = js::JSSLOT_PROXY_PRIVATE as uint;
// changes. // changes.
static DOM_PROTO_INSTANCE_CLASS_SLOT: u32 = 0; static DOM_PROTO_INSTANCE_CLASS_SLOT: u32 = 0;
// All DOM globals must have a slot at DOM_PROTOTYPE_SLOT. We have to // All DOM globals must have a slot at DOM_PROTOTYPE_SLOT.
// start at 1 past JSCLASS_GLOBAL_SLOT_COUNT because XPConnect uses pub static DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT;
// that one.
pub static DOM_PROTOTYPE_SLOT: u32 = js::JSCLASS_GLOBAL_SLOT_COUNT + 1;
// NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and // NOTE: This is baked into the Ion JIT as 0 in codegen for LGetDOMProperty and
// LSetDOMProperty. Those constants need to be changed accordingly if this value // LSetDOMProperty. Those constants need to be changed accordingly if this value
@ -580,6 +578,10 @@ pub impl WrapperCache {
self.wrapper = wrapper; self.wrapper = wrapper;
} }
fn get_rootable(&self) -> **JSObject {
return ptr::addr_of(&self.wrapper);
}
fn new() -> WrapperCache { fn new() -> WrapperCache {
WrapperCache { WrapperCache {
wrapper: ptr::null() wrapper: ptr::null()

View file

@ -16,7 +16,7 @@ use js::crust::{JS_PropertyStub, JS_StrictPropertyStub};
use js::global::jsval_to_rust_str; use js::global::jsval_to_rust_str;
use js::glue::bindgen::*; use js::glue::bindgen::*;
use js::glue::bindgen::RUST_JSVAL_TO_INT; use js::glue::bindgen::RUST_JSVAL_TO_INT;
use js::jsapi::bindgen::{JS_DefineFunctions}; use js::jsapi::bindgen::{JS_DefineFunctions, JS_GC, JS_GetRuntime};
use js::jsapi::bindgen::{JS_GetReservedSlot, JS_SetReservedSlot}; use js::jsapi::bindgen::{JS_GetReservedSlot, JS_SetReservedSlot};
use js::jsapi::bindgen::{JS_ValueToString}; use js::jsapi::bindgen::{JS_ValueToString};
use js::jsapi::{JSContext, JSVal, JSObject, JSBool, JSFreeOp, JSFunctionSpec}; use js::jsapi::{JSContext, JSVal, JSObject, JSBool, JSFreeOp, JSFunctionSpec};
@ -31,12 +31,15 @@ extern fn alert(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
assert!(argc == 1); assert!(argc == 1);
// Abstract this pattern and use it in debug, too? // Abstract this pattern and use it in debug, too?
let jsstr = JS_ValueToString(cx, *ptr::offset(argv, 0)); let jsstr = JS_ValueToString(cx, *ptr::offset(argv, 0));
if jsstr.is_null() {
return 0;
}
(*unwrap(JS_THIS_OBJECT(cx, vp))).payload.alert(jsval_to_rust_str(cx, jsstr)); (*unwrap(JS_THIS_OBJECT(cx, vp))).payload.alert(jsval_to_rust_str(cx, jsstr));
JS_SET_RVAL(cx, vp, JSVAL_NULL); JS_SET_RVAL(cx, vp, JSVAL_NULL);
return 1;
} }
1_i32
} }
extern fn setTimeout(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool { extern fn setTimeout(cx: *JSContext, argc: c_uint, vp: *JSVal) -> JSBool {
@ -63,6 +66,14 @@ extern fn close(cx: *JSContext, _argc: c_uint, vp: *JSVal) -> JSBool {
} }
} }
extern fn gc(cx: *JSContext, _argc: c_uint, _vp: *JSVal) -> JSBool {
unsafe {
let runtime = JS_GetRuntime(cx);
JS_GC(runtime);
return 1;
}
}
unsafe fn unwrap(obj: *JSObject) -> *rust_box<Window> { unsafe fn unwrap(obj: *JSObject) -> *rust_box<Window> {
let val = JS_GetReservedSlot(obj, 0); let val = JS_GetReservedSlot(obj, 0);
cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val)) cast::reinterpret_cast(&RUST_JSVAL_TO_PRIVATE(val))
@ -99,7 +110,14 @@ pub fn init(compartment: @mut Compartment) {
JSFunctionSpec { JSFunctionSpec {
name: compartment.add_name(~"close"), name: compartment.add_name(~"close"),
call: JSNativeWrapper { op: close, info: null() }, call: JSNativeWrapper { op: close, info: null() },
nargs: 2, nargs: 0,
flags: 0,
selfHostedName: null()
},
JSFunctionSpec {
name: compartment.add_name(~"_trigger_gc"),
call: JSNativeWrapper { op: gc, info: null() },
nargs: 0,
flags: 0, flags: 0,
selfHostedName: null() selfHostedName: null()
}, },

View file

@ -27,9 +27,9 @@ pub fn Document(root: AbstractNode,
}; };
let compartment = global_content().compartment.get(); let compartment = global_content().compartment.get();
do root.with_imm_node |node| { do root.with_imm_node |node| {
let wrapper = node.wrapper.get_wrapper(); assert!(node.wrapper.get_wrapper().is_not_null());
assert!(wrapper.is_not_null()); let rootable = node.wrapper.get_rootable();
unsafe { JS_AddObjectRoot(compartment.cx.ptr, ptr::addr_of(&wrapper)); } unsafe { JS_AddObjectRoot(compartment.cx.ptr, rootable); }
} }
document::create(compartment, doc); document::create(compartment, doc);
doc doc
@ -40,9 +40,9 @@ impl Drop for Document {
fn finalize(&self) { fn finalize(&self) {
let compartment = global_content().compartment.get(); let compartment = global_content().compartment.get();
do self.root.with_imm_node |node| { do self.root.with_imm_node |node| {
let wrapper = node.wrapper.get_wrapper(); assert!(node.wrapper.get_wrapper().is_not_null());
assert!(wrapper.is_not_null()); let rootable = node.wrapper.get_rootable();
unsafe { JS_RemoveObjectRoot(compartment.cx.ptr, ptr::addr_of(&wrapper)); } unsafe { JS_RemoveObjectRoot(compartment.cx.ptr, rootable); }
} }
} }
} }

View file

@ -20,13 +20,6 @@ pub struct Element {
attrs: ~[Attr], attrs: ~[Attr],
} }
#[unsafe_destructor]
impl Drop for Element {
fn finalize(&self) {
fail!(~"uh oh");
}
}
#[deriving(Eq)] #[deriving(Eq)]
pub enum ElementTypeId { pub enum ElementTypeId {
HTMLAnchorElementTypeId, HTMLAnchorElementTypeId,

View file

@ -1,3 +1,3 @@
div #styled { #styled {
color: red; color: red;
} }

View file

@ -4,6 +4,6 @@
<script src="test_hammer_layout.js"></script> <script src="test_hammer_layout.js"></script>
</head> </head>
<body> <body>
<div id="styled">This text is unstyled.</div> <div id="">This text is unstyled.</div>
</body> </body>
</html> </html>

View file

@ -1,17 +1,6 @@
window.setTimeout(function() { var divs = document.getElementsByTagName("div");
//var divs = document.getElementsByTagName("div"); var div = divs[0];
// divs[0].setAttribute('id', 'styled'); for (var i = 0; i < 1000000; i++) {
function print_tree(n) { div.setAttribute('id', 'styled');
window.alert(n.nodeType); }
//window.alert(n.tagName);
n = n.firstChild;
while (n) {
print_tree(n);
n = n.nextSibling;
}
}
print_tree(document.documentElement);
//window.alert(document.documentElement.tagName);
//window.alert(document.documentElement.firstChild.nodeType);
//window.alert(document.documentElement.firstChild.firstChild.nodeType);
}, 200);