Switch from heap/stack to just a heap

This commit switches strategies for storing `JsValue` from a heap/stack
to just one heap. This mirrors the new strategy for `JsValue` storage
in #1002 and should make multiplexing those strategies at
`wasm-bindgen`-time much easier.

Instead of having one array which acts as a stack for borrowed values
and one array for a heap of borrowed values, only one JS array is used
for storage of JS values now. This makes `getObject` far simpler by
simply being an array access, but it means that cloning an object now
reserves a new slot instead of reference counting it. If the old
reference counting behavior is needed it's thought that `Rc<JsValue>`
can be used in Rust.

The new "heap" has an initial stack pointer which grows downwards, and a
heap which grows upwards. The heap is a singly-linked-list which is
allocated/deallocated from. The stack grows downwards to zero and
presumably starts generating errors once it underflows. An initial stack
size of 32 is chosen as that should encompass all use cases today, but
we can eventually probably add configuration for this!

Note that the heap is initialized to all `null` for the stack and then
the initial JS values (`undefined`, `null`, `true`, `false`) are pushed
onto the heap in reserved locations.
This commit is contained in:
Alex Crichton
2018-11-29 18:15:36 -08:00
parent e746ad5a0a
commit 49d835a7bc
4 changed files with 137 additions and 250 deletions

View File

@ -67,11 +67,12 @@ pub struct JsValue {
_marker: marker::PhantomData<*mut u8>, // not at all threadsafe
}
const JSIDX_UNDEFINED: u32 = 0;
const JSIDX_NULL: u32 = 2;
const JSIDX_TRUE: u32 = 4;
const JSIDX_FALSE: u32 = 6;
const JSIDX_RESERVED: u32 = 8;
const JSIDX_OFFSET: u32 = 32; // keep in sync with js/mod.rs
const JSIDX_UNDEFINED: u32 = JSIDX_OFFSET + 0;
const JSIDX_NULL: u32 = JSIDX_OFFSET + 1;
const JSIDX_TRUE: u32 = JSIDX_OFFSET + 2;
const JSIDX_FALSE: u32 = JSIDX_OFFSET + 3;
const JSIDX_RESERVED: u32 = JSIDX_OFFSET + 4;
impl JsValue {
/// The `null` JS value constant.
@ -533,13 +534,12 @@ impl Drop for JsValue {
#[inline]
fn drop(&mut self) {
unsafe {
// The first bit indicates whether this is a stack value or not.
// Stack values should never be dropped (they're always in
// `ManuallyDrop`)
debug_assert!(self.idx & 1 == 0);
// We definitely should never drop anything in the stack area
debug_assert!(self.idx >= JSIDX_OFFSET);
// We don't want to drop the first few elements as they're all
// reserved, but everything else is safe to drop.
// Otherwise if we're not dropping one of our reserved values,
// actually call the intrinsic. See #1054 for eventually removing
// this branch.
if self.idx >= JSIDX_RESERVED {
__wbindgen_object_drop_ref(self.idx);
}