Quellcode durchsuchen

Switch model entirely. Go from flat vector maps to specialized skip list, add draft paper.

This commit is the single biggest architectural change in ralloc to
date. We go from using vector maps to a skip list variant.

- Introduce XORShift+ PRNG as backbone for the skip list level
  generation.
- Implement typed arenas.
- Introduce the `Jar` type representing an owned pointer.
- Make use of `usize` newtypes to improve segregation of various uses
  (we use a macro to derive these).
- Introduce `replace_with` to make it easier to gain temporary ownership
  of a value behind a pointer.
- Make all logging be done through a function in `shim` taking
  formatting arguments, line number, file name, kind, and log level,
  such that you can configure the output's formatting:
    * Buffer per bulk write.
    * Remove the line lock in favor of buffering and atomic writes.
    * Move the log function into a standalone file.
- Add more tests.
- Add message to the `must_use` attributes.

(This commit is WIP and cannot be regarded complete)
ticki vor 8 Jahren
Ursprung
Commit
8cd761bb91
32 geänderte Dateien mit 2120 neuen und 1324 gelöschten Zeilen
  1. 7 1
      .gitignore
  2. 1 1
      Cargo.toml
  3. 422 0
      paper/ralloc.tex
  4. 83 0
      shim/config.rs
  5. 18 11
      shim/src/config.rs
  6. 2 1
      shim/src/lib.rs
  7. 63 0
      shim/src/log.rs
  8. 2 2
      shim/src/thread_destructor.rs
  9. 5 29
      src/allocator.rs
  10. 277 0
      src/arena.rs
  11. 28 0
      src/bk/mod.rs
  12. 165 0
      src/bk/node.rs
  13. 98 0
      src/bk/pool.rs
  14. 317 0
      src/bk/seek.rs
  15. 132 0
      src/bk/shortcut.rs
  16. 35 27
      src/block.rs
  17. 0 956
      src/bookkeeper.rs
  18. 15 5
      src/brk.rs
  19. 27 2
      src/cell.rs
  20. 99 0
      src/derive.rs
  21. 0 2
      src/fail.rs
  22. 12 0
      src/lazy_init.rs
  23. 2 1
      src/leak.rs
  24. 11 5
      src/lib.rs
  25. 30 259
      src/log.rs
  26. 2 1
      src/prelude.rs
  27. 88 3
      src/ptr.rs
  28. 62 0
      src/random.rs
  29. 3 3
      src/sync.rs
  30. 71 0
      src/take.rs
  31. 32 5
      src/tls.rs
  32. 11 10
      src/vec.rs

+ 7 - 1
.gitignore

@@ -1,2 +1,8 @@
-target
+*.aux
+*.bin
+*.log
+*.out
+*.pdf
+*.toc
 Cargo.lock
+target

+ 1 - 1
Cargo.toml

@@ -20,7 +20,7 @@ path = "shim"
 version = "0.1"
 
 [dependencies.clippy]
-version = "0.0.85"
+version = "0.0"
 optional = true
 
 [profile.release]

+ 422 - 0
paper/ralloc.tex

@@ -0,0 +1,422 @@
+\documentclass[11pt]{article}
+\usepackage[T1]{fontenc}
+\usepackage{amsmath, amsfonts, amssymb, amsthm, url, algorithmicx,
+    algpseudocode, lmodern, color, graphicx}
+
+\providecommand{\floor}[1]{\left \lfloor #1 \right \rfloor }
+\providecommand{\NOTE}[1]{
+    \begin{center}
+        \fbox{\parbox{\textwidth}{\textbf{\textit{#1}}}}
+    \end{center}
+}
+\newcommand{\emod}{\ \rm mod \ }
+\newcommand{\ralloc}{\emph{ralloc} }
+
+\title{Ralloc -- An Efficient One-Fits-All General Memory Allocator}
+\author{Ticki\thanks{Thanks to Thomas Levy for helping with the implementation of \ralloc.}}
+\date{\today}
+
+\begin{document}
+    %%% DISCLAIMER %%%
+
+    \begin{titlepage}
+        \centering \huge\bfseries The following document is an incomplete draft.
+    \end{titlepage}
+
+    %%% START OF DOCUMENT %%%
+
+    \maketitle
+
+    \begin{abstract}
+        We present \ralloc, a novel memory allocation algorithm. In contrary to
+        many other memory allocator which are based on queues of similarly
+        sized blocks. \ralloc is built on a data structure, holding blocks of
+        arbitrarily sized, eliminating internal fragmentation, while preserving
+        a high performance. Furthermore, we show how this can be thread cached
+        to enable high performance under massive multi-threading.
+    \end{abstract}
+
+    \section{Introduction}
+    Memory allocators are a core component in modern software. The heap is
+    crucial to be able to store dynamically sized objects. Naturally, that
+    implies the need for high performance.
+
+    Unfortunately, modern memory allocators tend to be complex simply to
+    achieve a good performance. Complexity has its downside, from
+    maintainability to security. The core algorithm of \ralloc is relatively
+    simple and a basic implementation requires only 1000 CLOC.
+
+    This project was originally born out of the need of a general-purpose
+    userspace memory allocator for Redox -- The Rust
+    Operating-System\cite{redoxweb}, an OS in which all the core primitives are
+    written in the Rust programming language\cite{rustweb}.  This programming
+    language utilizes extensive static analysis methods which we use throughout
+    our implementation.
+
+    The primary concern of a good allocator is the trade-off between memory
+    usage and performance. \ralloc happens to perform well per memory usage,
+    and demonstrably too in performance.
+
+    \
+
+    The approach \ralloc takes is radically different from popular memory
+    allocators such as slab\cite{bonwick94}, slob\cite{mackall05}, and buddy
+    allocation\cite{knowlton65}. In particularly, we present a data structure
+    which keeps track of longest possible continuous free segment. We
+    represents this efficiently in a tree-like structure allowing us to query
+    blocks of satisfying some condition
+
+    %%% CORE %%%
+
+    \section{Blocks}
+    `Blocks' are the core primitive of \ralloc. Strictly speaking they're just
+    fat pointers\footnote{i.e. a pointer equipped with a size.} with some
+    additional invariants (disjointness and validity), which are maintained
+    through the affine type system of Rust.
+
+    Blocks represents some segment of memory and has certain operations which
+    preserves the invariants spaecified above.
+
+    \begin{description}
+        \item [split(block, position)] Split the block at some position.
+        \item [merge(block\textsubscript{1}, block\textsubscript{2})] Merge two
+            blocks.
+        \item [size(block)] Get the size of a block.
+        \item [align(align, block)] Split the block to align to some specified
+            alignment.
+    \end{description}
+
+    \subsection{Memory alignment}
+    Especially the last one is of interest. All alignment padding functions
+    satisfy
+
+    $$
+        \mathtt{aligner}(b) \equiv -b \pmod A
+    $$
+
+    The simplest one is
+
+    $$
+        \mathtt{aligner}(b) = -b \emod A
+    $$
+
+    Since $ \mathtt{aligner}(b) < A $, it tends to leave small, unusable blocks
+    back, which increases external fragmentation.
+
+    For this reason, we use a slightly more complex algorithm:
+
+    $$
+        \mathtt{aligner}(b) = \begin{cases}
+            b & \mbox{if } b|A \\
+            \floor{\frac{\mathtt{size}(b)}{2}} - (\floor{\frac{\mathtt{size}(b)}{2}} \emod A) & \mbox{if } \mathtt{size}(b) \geq 2A \\
+            -b \emod A  & \mbox{else}
+        \end{cases}
+    $$
+
+    By observation, this tends to reduce external fragmentation by an order of
+    magnitude.
+
+    \section{Memory bookkeeping}
+    \NOTE{This section was revided in multiple turns and is thus sketchy. Rewrite pending.}
+    In contrary to other interval data structure, we are not concerned with
+    overlaps, but rather querying blocks of some size. \ralloc is based on a
+    data structure in which every block is maximized such that it marks the
+    longest possible continuous segment, in other words we merge adjacent
+    blocks.
+
+    A list of blocks is stored in a data structure that resembles Skip Lists as
+    first described in \cite{pugh89} with $ p = {^1} / {_2} $.
+
+    \subsection{Efficiently querying blocks of some size or more}
+    Linear search through the list for a fitting block is rather slow,
+    especially in the case of high fragmentation. To deal with this problem, we
+    track the biggest skipped block. We call this block ``the fat block of a
+    shortcut''.
+
+    To update this value, you merely have to recurse over the levels. Note that
+    the average skip will have $ p^{-1} = 2 $ children\footnote{We use the term
+    "child" due to the analogy to binary trees.}.
+
+    \subsection{Insertion}
+    To preserve the invariant that every block is ``as long as possible'', i.e.
+    is never adjacent to neighbouring blocks, we need to handle the case of
+    adjacent insertion.
+
+    Let $ b $ be the block in question, then
+
+    \begin{description}
+        \item [Double adjacent] If $ b $ has adjacent blocks $ (a, c) \in L $.
+            Then remove $ c $ and set $$ a \gets \mathtt{merge}(a, b, c). $$
+        \item [Left adjacent] Else if $ a \in L $ is left adjacent to $ b $, then
+            set $$ a \gets \mathtt{merge}(a, b). $$
+        \item [Right adjacent] Else if $ c \in L $ is right adjacent to $ b $, then
+            set $$ c \gets \mathtt{merge}(b, c). $$
+        \item [No adjacent] Continue conventional Skip List insertion.
+    \end{description}
+
+    A simple trick can improve performance by avoiding to backtrack and update
+    the fat blocks in certain cases. When the pointer is overshot, set
+
+    $$
+        f \gets \max(f, \rm{size}(b))
+    $$
+
+    where $ f $ is size of the biggest skipped node, and $ b $ is the block
+    we're inserting. Assume that merging was not possible, in that case we
+    clear don't need backtracking.
+
+    Consider the configuration,
+
+    \begin{figure}
+        \caption{An example configuration.}
+
+        \NOTE{This diagram is totally useless right now. Improve it.}
+        \begin{center}
+            \scalebox{1.5}{
+                $ x \xrightarrow{a \xrightarrow{b \xrightarrow{c \longrightarrow d} e} f \xrightarrow{g \xrightarrow{h} i} j} y $
+            }
+        \end{center}
+    \end{figure}
+
+    % TODO: Use algorithmic to specify the algorithm.
+
+    \subsection{Cache efficiency}
+    Cache efficiency is a major problem regarding performance in pointer-based
+    structures. In the case of trees and linked list where each node contains a
+    pointer to its children or successor, cache misses can damage performance
+    severely.
+
+    To avoid this, we use a SLOB arena, which is a block we allocate and break
+    down to a linked list. This ensures that the nodes are scattered across few
+    cache lines.
+
+    \subsection{Metacircular allocation}
+    The structure maintains its own buffer. Despite it leading to complication,
+    it turns out to be faster than simply allocating it through the source
+    allocator (which we will explain in next section).
+
+    The main complication there is to this approach is the fact that replacing
+    the internal buffer actually needs allocation and thus results in unbounded
+    recursion. To solve this we maintain the arena to hold $ n $ more blocks
+    than needed whenever reallocation is inactive ($ n $ is implementation
+    defined).
+
+    Whenever reallocation is triggered (i.e. when the invariant is broken), a
+    flag is set, which disables the maintenance of said invariant; after the
+    reallocation is over we reset the flag.
+
+    \section{Avoiding locks}
+    Locking a global locks can hurt performance of an allocator severely.
+    \cite{manghwani05} analyze two different thread-caching methods.
+    Unfortunately, none of them are suited for an arbitrary-size allocator, so
+    we modify LLAlloc's approach.
+
+    \ralloc's ``source allocator'' is generic and that is exploited for thread
+    caching. In particular, we associate a local allocator with each thread.
+    All \ralloc bookkeeping is done in this allocator.
+
+    When the first \ralloc call of a thread is made, the allocator is
+    initialized and fueled by memory requested from the global allocator
+    (shared across threads and hidden behind a lock). Then a thread destructor
+    is said: when the thread exits the memory of the local allocator is freed
+    to the global allocator.
+
+    Whenever the local allocator is unable to serve the requested memory, the
+    global allocator is locked and used as source allocator.
+
+    \subsection{Local-to-global memory trimming}
+
+    Two new problems arises when introducing this form of thread caching:
+
+    \begin{enumerate}
+        \item There is increased external fragmentation in the case of
+            cross-thread frees, due to one thread getting the allocated buffer
+            and another getting the adjacent blocks.
+        \item If one thread allocates a large buffers, and then later frees it,
+            it ends up keeping inaccessible memory, which could be used in
+            other threads.
+    \end{enumerate}
+
+    To counter these problems, we implement memory trimming for the local to
+    the global allocator. What this essentially means is that the memory
+    trimming routine, which will free blocks to the global allocator until some
+    condition is met, is triggered when the allocator hits some memory limit or
+    some fragmentation limit.
+
+    We define a local allocator to have ``high fragmentation''
+    whenever\footnote{This is a rather simplistic measure, and will be improved
+        in the future.}
+
+    $$
+        t < cb
+    $$
+
+    with $ t $ being the total number of bytes contained in the allocator and $
+    b $ being the number of blocks.
+
+    When this condition is met or $ t > l $ for some constant $ l $, we free
+    local blocks until $ t < s $ for some constant $ s $.
+
+    \section{OS memory trimming}
+    For long running processes, memory peaks can be problematic if it is never
+    returned to the operating-system.
+
+    To avoid the case where the maximal memory usage is retained, we trim the
+    global allocator similarly to how we trim the local allocator, with the
+    exception of not measuring fragmentation.
+
+    When OS memory trimming is triggered, we go pop the last block and, if it
+    is big enough to be worthy to memory trim, we free it to the system. Since
+    blocks in the memory bookkeeper represent longest possible continuous
+    segments, we can at most memory trim one block.
+
+    \section{Canonicalization}
+    Both in cases of system source allocation (which we use BRK for) and global
+    source allocation, we are interested in reserving more than actually needed
+    to avoid the overhead of repeated calls.
+
+    Every request to the source allocator will be canonicalized by
+
+    $$
+        f_s(x) = x + \max(k_1, \min(k_2 x, k_3))
+    $$
+
+    To explain our reasoning, we essentially set a minimum extra space ($ k_1
+    $), and then define the excessive space as a multiple ($ k_2 $) of the
+    requested space bounded by some maximum extra space ($ k_3 $).
+
+    BRKs are especially expensive (they can even trigger remapping of the
+    process). For this reason, they need even higher canonicalization. For this
+    reason, we apply the same function but with stronger constants.
+
+    \section{Partial frees}
+    An interesting implication of our approach is the possibilities of
+    ``partial frees'', in which \emph{a part} of a buffer is deallocated. This
+    is not allowed in ``classical allocators'', but useful in some scenario.
+
+    \section{Adding libc malloc compatibility}
+    libc's allocation API diverges from Rust's in one major way: In libc the
+    only information provided upon reallocation and free is the pointer to the
+    buffer. In Rust's, however, the size of the allocation is provided as
+    well\cite{crichton15}.
+
+    This leads to interesting possibilities, mainly concerning the reduction
+    (or even complete removal -- as in \ralloc's case) of metadata of blocks.
+
+    The drawback is incompatibility. To solve this incompatibility, we encode
+    the buffer size into a metadata precursor of the buffer, when the
+    allocation is done through the libc API.
+
+    This metadata block is unaligned due to the blocks original alignment being
+    unknown. Before the metadata block we have an alignment padding block,
+    serving as aligning the allocated buffer.
+
+    When free or reallocation is invoked, we can obtain the size of the buffer
+    by simply reading this metadata block. This allows us to translate the libc
+    API calls into Rust-like allocation API calls.
+
+    %%% IMPLEMENTATION/PRACTICAL CONSIDERATION %%%
+
+    \section{Implementation}
+    \ralloc is a part of the Redox OS ecosystem and thus is, like all other
+    components, written in the Rust programming language. Rust puts great
+    emphasis on multithreading, and so does \ralloc.
+
+    Rust deploys a great deal of static analysis, which we naturally use to
+    improve correctness of \ralloc. The feature we use the most is affine
+    types, which themself are a form of substructural types where passing the
+    type ``moves'' it out of scope. This allows us to effectively reason about
+    things such as use-after-free and illegal aliasing.
+
+    Our implementation is written as semi-literate programming, and more than
+    half of the lines of code are API documentation or comments. This is a
+    deliberate choice, since we hope to force the programmer to think and
+    explain why the algorithm works, hopefully uncovering bugs in it.
+
+    \subsection{Debugging}
+    Our implementation deploys extensive debug checks. Every invariant is
+    carefully checked in ``debugging mode'', this allows for efficiently
+    uncovering subtle bugs.
+
+    Invariants which are relied on for safety (guarantees) are checked through
+    assertions, which are tested even in non-debug mode. Disassembling shows
+    that the vast majority of these are optimized out or have no impact on
+    performance\footnote{i.e. no observable difference is seen.}.
+
+    For a downstream user, who wish to debug their program, we make
+    configurable API calls to the debugger, informing about free and
+    uninitialized memory.
+
+    \subsection{Logging}
+    Everything is (optionally) logged to a configurable target. The log is
+    separated into multiple ``log levels'', an idea which is used in many
+    modern logging systems.
+
+    \subsection{Configuration}
+    Configuration is handled by linking to a shim library, which provides
+    constants and functions for binding and configuring \ralloc. This approach
+    saves \ralloc from the problems \texttt{mallopt}\footnote{The problems are
+        mainly caused by global configuration, in which querying a parameter
+        requires locking a global lock.}.
+
+    The downside being that \ralloc is no longer configurable at runtime.
+    This can be fixed by replacing the default shim implementation with a
+    custom one.
+
+    \section{Measuring performance}
+
+    \section{Limitations}
+
+    %%% CLOSING WORDS %%%
+
+    \section{Future work}
+
+    We are interested in investigating storing the original thread of an
+    allocated buffer to be able to return it and reduce external fragmentation.
+    The thread is represented by a pointer to some concurrent channel, which
+    is used to pass over the block in case of cross-thread drops. Naturally, to
+    avoid alignment issues we place this pointer after the buffer. This has the
+    positive side-effect of revealing buffer overruns by damaging the pointer
+    and likely producing a segmentation fault.
+
+    \section{Thanks to}
+
+    Special thanks to Thomas Levy, whom helped implementing and developing
+    \ralloc.
+
+    %%% BIBLIOGRAPHY %%%
+
+    \begin{thebibliography}{9}
+        \bibitem{redoxweb}
+            \url{http://redox-os.org},
+            retrieved \today
+        \bibitem{rustweb}
+            \url{http://rust-lang.org},
+            retrieved \today
+        \bibitem{bonwick94}
+            Jeff Bonwick,
+            \emph{The Slab Allocator: An Object-Caching Kernel Memory Allocator},
+            1994
+        \bibitem{mackall05}
+            Matt Mackall,
+            ``slob: introduce the SLOB allocator'',
+            Linux Mailing List,
+            2005
+        \bibitem{knowlton65}
+             Kenneth C. Knowlton,
+             \emph{A Fast storage allocator},
+             1966
+        \bibitem{pugh89}
+            William Pugh,
+            \emph{Skip Lists: A Probabilistic Alternative to Balanced Trees},
+            1989
+        \bibitem{manghwani05}
+             Rahul Manghwani and Tao He,
+             \emph{Scalable Memory Allocation},
+             2005
+        \bibitem{crichton15}
+            Alex Crichton,
+            ``RFC: Allow changing the default allocator'',
+            2015
+    \end{thebibliography}
+\end{document}

+ 83 - 0
shim/config.rs

@@ -0,0 +1,83 @@
+//! Configuration.
+//!
+//! This module contains anything which can be tweaked and customized to the users preferences.
+
+use core::{intrinsics, cmp, fmt};
+
+/// The memtrim limit.
+///
+/// Whenever this is exceeded, the allocator will try to free as much memory to the system
+/// as it can.
+pub const OS_MEMTRIM_LIMIT: usize = 200000000;
+/// Minimum size before a block is worthy to memtrim.
+pub const OS_MEMTRIM_WORTHY: usize = 4000;
+
+/// The fragmentation scale constant.
+///
+/// This is used for determining the minimum avarage block size before locally memtrimming.
+pub const FRAGMENTATION_SCALE: usize = 10;
+/// The local memtrim limit.
+///
+/// Whenever an local allocator has more free bytes than this value, it will be memtrimmed.
+pub const LOCAL_MEMTRIM_LIMIT: usize = 16384;
+/// The local memtrim chock.
+///
+/// The local memtrimming will continue until the allocator has less memory (in bytes, of course)
+/// than this value.
+pub const LOCAL_MEMTRIM_STOP: usize = 1024;
+
+/// The default OOM handler.
+#[cold]
+pub fn default_oom_handler() -> ! {
+    // Log some message.
+    log(6, "ERROR", "\x1b[31;1mThe application ran out of memory. Aborting.", file!(), line!());
+
+    unsafe {
+        intrinsics::abort();
+    }
+}
+
+/// Canonicalize a fresh allocation.
+///
+/// The return value specifies how much _more_ space is requested to the fresh allocator.
+#[inline]
+pub fn extra_fresh(size: usize) -> usize {
+    /// The multiplier.
+    ///
+    /// The factor determining the linear dependence between the minimum segment, and the acquired
+    /// segment.
+    const MULTIPLIER: usize = 2;
+    /// The minimum extra size to be BRK'd.
+    const MIN_EXTRA: usize = 512;
+    /// The maximal amount of _extra_ bytes.
+    const MAX_EXTRA: usize = 1024;
+
+    cmp::max(MIN_EXTRA, cmp::min(MULTIPLIER * size, MAX_EXTRA))
+}
+
+/// Canonicalize a BRK request.
+///
+/// Syscalls can be expensive, which is why we would rather accquire more memory than necessary,
+/// than having many syscalls acquiring memory stubs. Memory stubs are small blocks of memory,
+/// which are essentially useless until merge with another block.
+///
+/// To avoid many syscalls and accumulating memory stubs, we BRK a little more memory than
+/// necessary. This function calculate the memory to be BRK'd based on the necessary memory.
+///
+/// The return value specifies how much _more_ space is requested.
+// TODO: Move to shim.
+#[inline]
+pub fn extra_brk(size: usize) -> usize {
+    // TODO: Tweak this.
+    /// The BRK multiplier.
+    ///
+    /// The factor determining the linear dependence between the minimum segment, and the acquired
+    /// segment.
+    const MULTIPLIER: usize = 4;
+    /// The minimum extra size to be BRK'd.
+    const MIN_EXTRA: usize = 8192;
+    /// The maximal amount of _extra_ bytes.
+    const MAX_EXTRA: usize = 131072;
+
+    cmp::max(MIN_EXTRA, cmp::min(MULTIPLIER * size, MAX_EXTRA))
+}

+ 18 - 11
shim/src/config.rs

@@ -2,7 +2,7 @@
 //!
 //! This module contains anything which can be tweaked and customized to the users preferences.
 
-use core::{intrinsics, cmp};
+use core::{intrinsics, cmp, fmt};
 
 /// The memtrim limit.
 ///
@@ -25,15 +25,18 @@ pub const LOCAL_MEMTRIM_LIMIT: usize = 16384;
 /// The local memtrimming will continue until the allocator has less memory (in bytes, of course)
 /// than this value.
 pub const LOCAL_MEMTRIM_STOP: usize = 1024;
-
+/// The log target's file descriptor.
+pub(crate) const LOG_TARGET: i32 = 2;
 /// The minimum log level.
-pub const MIN_LOG_LEVEL: u8 = 0;
+pub(crate) const MIN_LOG_LEVEL: u8 = 0;
+/// The message buffer size (in bytes).
+pub(crate) const LOG_BUFFER_SIZE: usize = 128;
 
 /// The default OOM handler.
 #[cold]
 pub fn default_oom_handler() -> ! {
     // Log some message.
-    log("\x1b[31;1mThe application ran out of memory. Aborting.\x1b[m\n");
+    log(6, "ERROR", "\x1b[31;1mThe application ran out of memory. Aborting.", file!(), line!());
 
     unsafe {
         intrinsics::abort();
@@ -43,14 +46,18 @@ pub fn default_oom_handler() -> ! {
 /// Write to the log.
 ///
 /// This points to stderr, but could be changed arbitrarily.
-pub fn log(s: &str) -> usize {
-    unsafe { syscall!(WRITE, 2, s.as_ptr(), s.len()) }
+pub fn log(lv: u8, kind: &str, args: fmt::Arguments, file: &str, line: u32) {
+    /// The minimum log level.
+    const MIN_LOG_LEVEL: u8 = 0;
+
+    if lv >= MIN_LOG_LEVEL {
+        unsafe { syscall!(WRITE, 2, s.as_ptr(), s.len()) }
+    }
 }
 
 /// Canonicalize a fresh allocation.
 ///
 /// The return value specifies how much _more_ space is requested to the fresh allocator.
-// TODO: Move to shim.
 #[inline]
 pub fn extra_fresh(size: usize) -> usize {
     /// The multiplier.
@@ -59,7 +66,7 @@ pub fn extra_fresh(size: usize) -> usize {
     /// segment.
     const MULTIPLIER: usize = 2;
     /// The minimum extra size to be BRK'd.
-    const MIN_EXTRA: usize = 64;
+    const MIN_EXTRA: usize = 512;
     /// The maximal amount of _extra_ bytes.
     const MAX_EXTRA: usize = 1024;
 
@@ -84,11 +91,11 @@ pub fn extra_brk(size: usize) -> usize {
     ///
     /// The factor determining the linear dependence between the minimum segment, and the acquired
     /// segment.
-    const MULTIPLIER: usize = 2;
+    const MULTIPLIER: usize = 4;
     /// The minimum extra size to be BRK'd.
-    const MIN_EXTRA: usize = 1024;
+    const MIN_EXTRA: usize = 8192;
     /// The maximal amount of _extra_ bytes.
-    const MAX_EXTRA: usize = 65536;
+    const MAX_EXTRA: usize = 131072;
 
     cmp::max(MIN_EXTRA, cmp::min(MULTIPLIER * size, MAX_EXTRA))
 }

+ 2 - 1
shim/src/lib.rs

@@ -15,6 +15,7 @@
 extern crate syscall;
 
 pub mod config;
-pub mod thread_destructor;
 pub mod debug;
+pub mod log;
 pub mod syscalls;
+pub mod thread_destructor;

+ 63 - 0
shim/src/log.rs

@@ -0,0 +1,63 @@
+//! Allocator logging.
+
+use core::{fmt, mem};
+
+use config;
+
+// TODO: Consider implementing flushing.
+
+/// Write to the log.
+///
+/// This points to stderr, but could be changed arbitrarily.
+pub fn write(lv: u8, kind: &str, args: fmt::Arguments, file: &str, line: u32) {
+    if lv >= config::MIN_LOG_LEVEL {
+        // The buffer. We add an extra slot, which is reserved for overflows. If the buffer is
+        // filled, we will insert a "..." character to inform the user that there is more in this
+        // message. We start out with all dots, so we don't have to set these up later on in case
+        // of the buffer being full.
+        let mut buffer = [b'.'; config::LOG_BUFFER_SIZE + 3];
+
+        // The bytes of the buffer that are filled.
+        let mut filled;
+
+        {
+            // We emulate the writing semantics by having a newtype which implements `fmt::Write`. All
+            // this type does is holding a slice, which is updated when new bytes are written. This
+            // slice will point to the buffer declared above.
+            let mut writer = BufWriter {
+                buffer: &mut buffer[..config::LOG_BUFFER_SIZE],
+            };
+            write!(writer, "{:10}{:60} (@ {}:{})", kind, args, file, line).unwrap();
+            filled = config::LOG_BUFFER_SIZE - writer.buffer.len();
+        }
+
+        // Write the dots to the end if the buffer was full.
+        if filled == config::LOG_BUFFER_SIZE {
+            filled += 3;
+        }
+
+        // Finally, write it to the logging target.
+        assert!(unsafe {
+            syscall!(WRITE, config::LOG_TARGET, &buffer[0], filled)
+        } != !0, "Failed to write to logging target.");
+    }
+}
+
+/// A logging buffer.
+///
+/// This simply keeps track of the buffer by maintaining a slice representing the remaining part of
+/// the buffer.
+struct BufWriter<'a> {
+    /// A view into the remaining part of the buffer.
+    buffer: &'a mut [u8],
+}
+
+impl<'a> fmt::Write for BufWriter<'a> {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        let amt = cmp::min(s.len(), self.buffer.len());
+        let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
+        a.copy_from_slice(&s.as_bytes()[..amt]);
+
+        Ok(())
+    }
+}

+ 2 - 2
shim/src/thread_destructor.rs

@@ -16,7 +16,7 @@ pub mod arch {
 
     /// Register a thread destructor.
     // TODO: Due to rust-lang/rust#18804, make sure this is not generic!
-    pub fn register(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+    pub unsafe fn register(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
         use core::mem;
 
         /// A thread destructor.
@@ -40,7 +40,7 @@ pub mod arch {
     }
 
     /// Register a thread destructor.
-    pub fn register(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+    pub unsafe fn register(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
         _tlv_atexit(dtor, t);
     }
 }

+ 5 - 29
src/allocator.rs

@@ -4,7 +4,7 @@
 
 use prelude::*;
 
-use core::{mem, ops};
+use core::mem;
 
 use {brk, sync};
 use bookkeeper::{self, Bookkeeper, Allocator};
@@ -63,6 +63,7 @@ macro_rules! get_allocator {
                     log!(WARNING, "Accessing the allocator after deinitialization of the local allocator.");
 
                     // Lock the global allocator.
+                    log!(DEBUG, "Locking global allocator.");
                     let mut guard = GLOBAL_ALLOCATOR.lock();
 
                     // Call the block in question.
@@ -76,6 +77,7 @@ macro_rules! get_allocator {
         #[cfg(not(feature = "tls"))]
         {
             // Lock the global allocator.
+            log!(DEBUG, "Locking global allocator.");
             let mut guard = GLOBAL_ALLOCATOR.lock();
 
             // Call the block in question.
@@ -85,27 +87,6 @@ macro_rules! get_allocator {
     }}
 }
 
-/// Derives `Deref` and `DerefMut` to the `inner` field.
-///
-/// This requires importing `core::ops`.
-macro_rules! derive_deref {
-    ($imp:ty, $target:ty) => {
-        impl ops::Deref for $imp {
-            type Target = $target;
-
-            fn deref(&self) -> &$target {
-                &self.inner
-            }
-        }
-
-        impl ops::DerefMut for $imp {
-            fn deref_mut(&mut self) -> &mut $target {
-                &mut self.inner
-            }
-        }
-    };
-}
-
 /// Global SBRK-based allocator.
 ///
 /// This will extend the data segment whenever new memory is needed. Since this includes leaving
@@ -119,7 +100,6 @@ struct GlobalAllocator {
 impl GlobalAllocator {
     /// Initialize the global allocator.
     fn init() -> GlobalAllocator {
-        /// Logging...
         log!(NOTE, "Initializing the global allocator.");
 
         // The initial acquired segment.
@@ -169,7 +149,6 @@ impl Allocator for GlobalAllocator {
 
             // Check if the memtrim is worth it.
             if block.size() >= config::OS_MEMTRIM_WORTHY {
-                /// Logging...
                 log!(NOTE, "Memtrimming the global allocator.");
 
                 // Release the block to the OS.
@@ -183,7 +162,6 @@ impl Allocator for GlobalAllocator {
                 // segments being as long as possible. For that reason, repeating to push and
                 // release would fail.
             } else {
-                /// Logging...
                 log!(WARNING, "Memtrimming for the global allocator failed.");
 
                 // Push the block back.
@@ -203,16 +181,15 @@ pub struct LocalAllocator {
     inner: Bookkeeper,
 }
 
+#[cfg(feature = "tls")]
 impl LocalAllocator {
     /// Initialize the local allocator.
-    #[cfg(feature = "tls")]
     fn init() -> LocalAllocator {
         /// The destructor of the local allocator.
         ///
         /// This will simply free everything to the global allocator.
         extern fn dtor(alloc: &ThreadLocalAllocator) {
-            /// Logging...
-            log!(NOTE, "Deinitializing and freeing the local allocator.");
+            log!(NOTE, "Deinitializing and freeing the local allocator to the global allocator.");
 
             // This is important! The thread destructors guarantee no other, and thus one could use the
             // allocator _after_ this destructor have been finished. In fact, this is a real problem,
@@ -232,7 +209,6 @@ impl LocalAllocator {
             alloc.into_inner().inner.for_each(move |block| global_alloc.free(block));
         }
 
-        /// Logging...
         log!(NOTE, "Initializing the local allocator.");
 
         // The initial acquired segment.

+ 277 - 0
src/arena.rs

@@ -0,0 +1,277 @@
+//! Fixed-size arenas.
+//!
+//! This module contains primitives for typed, fixed-size arenas, implemented as linked list. This
+//! allows for cache-efficient allocation and deallocation of fixed blocks.
+
+use prelude::*;
+
+use core::{ptr, mem, marker};
+
+use take;
+
+/// A linked-list of pointers.
+///
+/// This is similar to a nodeless linked list. We use this internally to implement arenas.
+///
+/// Any linking pointer must point to a valid buffer of minimum pointer size.
+#[derive(Default)]
+struct PointerList {
+    /// The head link of the list.
+    head: Option<Pointer<PointerList>>,
+}
+
+impl PointerList {
+    // Pop the head of the list.
+    //
+    // Return `None` if the list is empty.
+    #[inline]
+    fn pop(&mut self) -> Option<Pointer<u8>> {
+        if let Some(head) = self.head {
+            // Get the head pointer.
+            let res = head.clone().cast();
+
+            unsafe {
+                // LAST AUDIT: 2016-08-24 (Ticki).
+
+                // Set the head to the tail. Note that we keep this safe by maintaining the
+                // invariants.
+                *self = ptr::read(*head);
+            }
+
+            Some(res)
+        } else {
+            // The head is `None`, thus the list is empty.
+            None
+        }
+    }
+
+    /// Push a pointer to the top of the list.
+    ///
+    /// # Safety.
+    ///
+    /// This is unsafe due to holding the invariant that it is valid.
+    #[inline]
+    unsafe fn push(&mut self, ptr: Pointer<PointerList>) {
+        take::replace_with(self, |x| {
+            // Set the head to the pointer.
+            x.head = Some(ptr.cast());
+            // Move the list to `ptr`.
+            **ptr.cast() = x;
+
+            ptr
+        })
+    }
+}
+
+/// A typed arena.
+///
+/// This represented as a linked list of free blocks. The links them self are placed in the free
+/// segments, making it entirely zero-cost.
+///
+/// `T` is guaranteed to be larger than pointer size (this is due to the necessity of being able to
+/// fill in the free segments with pointer to the next segment).
+pub struct Arena<T> {
+    /// The internal list.
+    list: PointerList,
+    /// Phantom data.
+    _phantom: marker::PhantomData<T>,
+}
+
+impl<T> Arena<T> {
+    /// Create a new empty arena.
+    ///
+    /// # Panics
+    ///
+    /// This method will panic if a pointer is unable to fit the size of the type.
+    #[inline]
+    pub fn new() -> Arena<T> {
+        // Make sure the links fit in.
+        assert!(mem::size_of::<T>() >= mem::size_of::<PointerList>(), "Arena list is unable to \
+                contain a link (type must be pointer sized or more).");
+
+        Arena {
+            list: PointerList::default(),
+            _phantom: marker::PhantomData,
+        }
+    }
+
+    /// Allocate a jar with some initial value.
+    #[inline]
+    pub fn alloc(&mut self, inner: T) -> Result<Jar<T>, ()> {
+        if let Some(ptr) = self.list.pop() {
+            // Note that this cast is valid due to the correctness of the `free` method (i.e. the
+            // pointer is valid for `T`).
+            let ptr = ptr.cast();
+
+            // Gotta catch 'em bugs.
+            debug_assert!(ptr.aligned_to(mem::align_of::<T>()), "Arena contains unaligned pointers.");
+
+            unsafe {
+                // LAST AUDIT: 2016-08-23 (Ticki).
+
+                // Initialize the inner value. To avoid calling destructors on initialized values,
+                // we user raw writes instead.
+                mem::write(*ptr, inner);
+
+                // Convert it to a `Jar` and we're ready to go!
+                Ok(Jar::from_raw(ptr))
+            }
+        } else {
+            // List empty :(.
+            Err(())
+        }
+    }
+
+    /// Free a jar to the arena.
+    #[inline]
+    pub fn free(&mut self, jar: Jar<T>) {
+        unsafe {
+            // LAST AUDIT: 2016-08-23 (Ticki).
+
+            // TODO: Mark this as free.
+            self.list.push(Pointer::from(jar).cast());
+        }
+    }
+
+    /// Provide this arena with some block.
+    ///
+    /// This is used to fill the arena with memory from some source by essentially breaking the
+    /// block up and linking each piece together.
+    ///
+    /// # Panics
+    ///
+    /// This will hit an assertion if `T`'s size doesn't divide the block's size.
+    #[inline]
+    pub fn provide(&mut self, block: Block) {
+        // Some assertions...
+        assert!(block.size() % mem::size_of::<T>() == 0, "`T`'s size does not divide the block's.");
+        assert!(block.aligned_to(mem::align_of::<T>()) == 0, "Block is unaligned to `T`.");
+
+        // We log for convenience.
+        log!(DEBUG, "Providing {:?} to arena.", block);
+
+        // Calculate the end pointer.
+        let end = Pointer::from(block.empty_right()).cast();
+        // Calculate the start pointer.
+        let mut ptr: Pointer<PointerList>: Pointer::from(block).cast();
+
+        loop {
+            // We offset the current pointer to get the pointer to the next piece, which will
+            // define the value we will put at `ptr`.
+            // NB: We do not use `offset` because it asserts that we're inbound. Breaking this
+            // invariant would lead to undefined behavior. Instead we do custom convert'n'add
+            // arithmetic on the pointer.
+            let next_ptr = Pointer::new((*ptr.clone() as usize + mem::size_of::<PointerList>()) as *mut PointerList);
+
+            // If the new pointer goes beyond the end, we're done.
+            if next_ptr == end {
+                // We reached the end, so we leave a `None`.
+                *ptr = PointerList {
+                    head: None,
+                }
+
+                break;
+            }
+
+            // Make the piece point to the next piece.
+            *ptr = PointerList {
+                head: Some(next_ptr),
+            };
+            // Update the pointer counter.
+            ptr = next_ptr;
+        }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use prelude::*;
+
+    use brk;
+
+    /// Helper method to make an artificial arena.
+    fn make<T>() -> Arena<T> {
+        let mut arena = Arena::new();
+        arena.provide(brk::lock().sbrk(1024).unwrap());
+
+        arena
+    }
+
+    #[test]
+    fn test_integers() {
+        let mut arena = make();
+
+        let mut n = arena.alloc(200).unwrap();
+        assert_eq!(*n, 200);
+        *n = 400;
+        assert_eq!(*n, 400);
+        *n = 1;
+        assert_eq!(*n, 1);
+        arena.free(n);
+
+        let mut n = arena.alloc(543).unwrap();
+        assert_eq!(*n, 543);
+        *n = 402;
+        assert_eq!(*n, 402);
+        *n = 2;
+        assert_eq!(*n, 2);
+        arena.free(n);
+    }
+
+    #[test]
+    fn test_oom() {
+        let mut arena = make();
+
+        // Make the arena run dry.
+        while arena.alloc('a').is_ok() {}
+
+        arena.alloc(2).unwrap_err();
+        arena.alloc(2).unwrap_err();
+        arena.alloc(2).unwrap_err();
+        arena.alloc(2).unwrap_err();
+        arena.alloc(2).unwrap_err();
+        arena.alloc(2).unwrap_err();
+        arena.alloc(2).unwrap_err();
+        arena.alloc(2).unwrap_err();
+
+        let mut arena2 = make();
+
+        while let Ok(x) = arena2.alloc('b') {
+            arena.free(x);
+        }
+
+        arena.alloc(2).unwrap();
+        arena.alloc(2).unwrap();
+        arena.alloc(2).unwrap();
+        arena.alloc(2).unwrap();
+        arena.alloc(2).unwrap();
+        arena.alloc(2).unwrap();
+        arena.alloc(2).unwrap();
+        arena.alloc(2).unwrap();
+    }
+
+    #[test]
+    fn test_cross_arena() {
+        let mut arena1 = make();
+        let mut arena2 = make();
+
+        let mut n = arena1.alloc(200).unwrap();
+        assert_eq!(*n, 200);
+        *n = 400;
+        assert_eq!(*n, 400);
+        *n = 1;
+        assert_eq!(*n, 1);
+        arena2.free(n);
+
+        let mut n = arena2.alloc(543).unwrap();
+        assert_eq!(*n, 543);
+        *n = 402;
+        assert_eq!(*n, 402);
+        *n = 2;
+        assert_eq!(*n, 2);
+        arena1.free(n);
+
+        arena2.alloc(22).unwrap_err();
+        arena1.alloc(22).unwrap();
+    }
+}

+ 28 - 0
src/bk/mod.rs

@@ -0,0 +1,28 @@
+/// Memory bookkeeping.
+///
+/// This module is the core of `ralloc`, it contains efficient structures for storing and
+/// organizing memory, as well as finding fitting blocks and so on.
+///
+/// It is based around **a variant of skip lists**, which allow for very efficient searching. The
+/// primary idea is to keep continuous segments maximal by merging adjacent blocks.
+///
+/// Furthermore, every node keeps track of its "children's" (skipped nodes') largest block to
+/// allow refinement search guided by that value as well.
+///
+/// Many of these algorithms are super complex, so it is important that they're throughoutly
+/// commented and documented to make sure the code is readable in the future.
+///
+///     /------------------------------------------\
+///     | Welcome to the dark corner of `ralloc`,  |
+///     | have fun, and may the red ox be with you |
+///     \-------------v----------------------------/
+///                &   &
+///        _________&_&
+///      ~/  \  /  c  -\
+///     / |  /  \   \   \
+///       |    __    \__.
+///       |_!_|  |_!_|
+
+mod node;
+mod seek;
+mod shortcut;

+ 165 - 0
src/bk/node.rs

@@ -0,0 +1,165 @@
+/// A block list node.
+///
+/// 
+struct Node {
+    /// The inner block.
+    ///
+    /// This should never be empty (zero-sized).
+    block: Block,
+    /// The node that follows this node.
+    ///
+    /// This cannot be adjacent (tangent) to `self.block`. It is important to maintain the blocks
+    /// as long as possible, and hence merge if that is the case.
+    ///
+    /// `None` indicates that the node is the last node in the list.
+    next: Option<Jar<Node>>,
+    /// Shortcuts/jumps of the current node.
+    ///
+    /// This is a stack of linked list nodes, such that any entry has a list which is a superset of
+    /// the latter. The lowest layer is a subset of the block list itself.
+    ///
+    /// ```
+    /// ...
+    /// 2      # ---------------------> [6] ---------------------> [9] -------------> NIL
+    /// 1      # ---------------------> [6] ---> [7] ------------> [9] -------------> NIL
+    /// 0      # ------------> [5] ---> [6] ---> [7] ------------> [9] ---> [10] ---> NIL
+    /// bottom # ---> [1] ---> [5] ---> [6] ---> [7] ---> [8] ---> [9] ---> [10] ---> NIL
+    /// ```
+    ///
+    /// As a result the lowest entry is the most dense.
+    ///
+    /// If we assume our node is `[6]`, the stack would contain shotcuts to 7, 7, and 8, in that
+    /// order. The rest would simply be null pointers with fat value 0.
+    shortcuts: [Shortcut; LEVELS],
+}
+
+impl Node {
+    // TODO: Implement `IntoIterator`.
+    fn iter(&mut self) -> PoolIter {
+        PoolIter {
+            node: Some(self),
+        }
+    }
+
+    fn shortcuts(&self, lv: shotcut::Level) -> ShortcutIter {
+        ShortcutIter {
+            lv: lv,
+            node: Some(self),
+        }
+    }
+
+    /// Calculate the fat value at some level based on the level below and the inner block's size.
+    ///
+    /// This will simply traverse the layer below (given in the form of an iterator) and find the
+    /// maximal fat value. The result is guaranteed to be equal to or greater than
+    /// `self.block.size()`.
+    fn calculate_fat_value<I>(&self, lv: shortcut::Level, below: I) -> block::Size
+        where I: Iterator<Item = &Node> {
+        // We start at the block's size.
+        let mut new_fat = 0;
+
+        // The current skip at `lv`.
+        let shortcut = &self.shortcuts[lv];
+        // Avoid multiple checking branches for the sake of performance.
+        let next_node = shortcut.next.get().unwrap();
+
+        // Follow the shortcuts until we reach `new_node`.
+        // TODO: Unroll the first iteration of the loop below to avoid the unneccesary
+        // branch in the first iteration's call of `cmp::max`.
+        for i in below {
+            new_fat = cmp::max(i.fat, new_fat);
+
+            // Check if the next node isn't reached yet.
+            if i == next_node {
+                break;
+            }
+
+            // We short-circuit in case we reached the old fat value, since the nodes
+            // are bounded by this size and thus no bigger nodes are to be found.
+            if new_fat == shortcut.fat {
+                break;
+            }
+
+            // A note on code style: While it would be more idiomatic to make the above two
+            // conditionals above into a `take_while` iterator. Unfortunately, this
+            // introduces two (!) branches. Iterator adapters are not as zero-cost as
+            // everybody claims.
+        }
+
+        new_fat
+    }
+
+    /// Calculate the fat value of a non bottom layer (i.e. level is greater than or equal to one).
+    pub fn calculate_fat_value_non_bottom(&self, lv: shotcut::Level) -> block::Size {
+        // Since `lv != 0` decrementing will not underflow.
+        self.calculate_fat_value(lv, self.shortcuts[lv - 1].shortcuts(lv - 1))
+    }
+
+    /// Calculate the fat value of the lowest level.
+    pub fn calculate_fat_value_bottom(&self) -> block::Size {
+        // We base the new fat value of the lowest layer on the block list.
+        self.calculate_fat_value(Level(0), self.iter());
+    }
+
+    /// Check that this structure satisfy its invariants.
+    ///
+    /// This is NOP in release mode (`debug_assertions` disabled).
+    #[inline]
+    fn check(&self) {
+        if cfg!(debug_assertions) {
+            // Check against empty blocks.
+            assert!(!self.block.is_empty(), "Node's block {:?} is empty (zero sized)", self.block);
+
+            if let Some(next) = self.next {
+                // First, make sure that our node is sorted with respect to the next node.
+                assert!(next > self.block, "Node holding block {:?} is not sorted wrt. the next \
+                        block {:?}", self.block, next);
+
+                // The nodes may never be adjacent. If they are, a merge have been missed.
+                assert!(!self.block.left_to(next), "Node's block {:?} adjacent to the next node's \
+                        block {:?}", self.block, next);
+            }
+
+            // WHO'S A GOOD BOY???
+            //                .--~~,__
+            //   :-....,-------`~~'._.'
+            //    `-,,,  ,_      ;'~U'
+            //     _,-' ,'`-__; '--.
+            //    (_/'~~      ''''(;
+
+            // FIXME: The short-circuit in `calculate_fat_value` makes the check incomplete, if a
+            // larger element follows.
+
+            // Check the fat value of the bottom level.
+            assert!(self.shortcuts[0].fat == self.calculate_fat_value_bottom(), "The bottom layer's \
+                    fat value does not match the calculated fat value.");
+
+            // Check the fat values of the non bottom level.
+            for lv in shortcut::level_iter().skip(1) {
+                assert!(self.shortcuts[lv.into()].fat == self.calculate_fat_value_non_bottom(lv), "The \
+                        bottom layer's fat value does not match the calculated fat value.");
+            }
+
+            // Check that the shortcut refers to a node with appropriate (equal to or greater)
+            // height.
+            // FIXME: Fold this loop to the one above.
+            for lv in shortcut::level_iter() {
+                assert!(!self.shortcuts[lv.into()].next.shortcuts[lv.into()].is_null(), "Shortcut \
+                        points to a node with a lower height. Is this a dangling pointer?");
+            }
+        }
+    }
+}
+
+struct PoolIter<'a> {
+    node: Option<&'a mut Node>,
+}
+
+impl<'a> Iterator for PoolIter<'a> {
+    type Item = &'a mut Node;
+
+    fn next(&mut self) -> &'a mut Node {
+        // Replace `self.node` by the next shortcut, and return the old value.
+        mem::replace(&mut self.node, self.node.and_then(|x| &mut x.next))
+    }
+}

+ 98 - 0
src/bk/pool.rs

@@ -0,0 +1,98 @@
+use prelude::*;
+
+use core::{cmp, mem};
+
+use arena::Arena;
+use random;
+
+struct Pool {
+    head: Node,
+    arena: Arena<Node>,
+}
+
+impl Pool {
+    fn search(&mut self, block: Block) -> Seek {
+        log!(DEBUG, "Searching the block pool for block {:?}...", block);
+
+        // We start by an uninitialized value, which we fill out.
+        let mut seek = unsafe { mem::uninitialized() };
+
+        // The outline of the algorithm is this: We start by shortcutting from the top level until
+        // we overshoot, then we repeat on the next level starting at the last non-overshot
+        // shortcut from the previous level.
+
+        // If we look for 8, we start in the top level and follow until we hit 9.
+        //     # ~~~~~~~~~~~~~~~~~~> [6] --- overshoot ----> [9] -----------> NIL
+        //     # ------------------> [6] --> [7] ----------> [9] -----------> NIL
+        //     # ----------> [5] --> [6] --> [7] ----------> [9] --> [10] --> NIL
+        //     # --> [1] --> [5] --> [6] --> [7] --> [8] --> [9] --> [10] --> NIL
+
+        // Start at the highest (least dense) level.
+        let mut iter = self.head.shortcuts(shortcut::Level::max());
+        // Go forward until we overshoot.
+        while let Some(shortcut_taken) = iter.take_while(|x| x < block).last() {
+
+            // Decrement the level.
+            let shortcut::Level(lv) = iter.decrement_level();
+            log!(INTERNAL, "Going from level {} to level {}.", lv, lv - 1);
+
+            // Update the back look respectively.
+            seek.back_look[lv] = shortcut_taken;
+
+            // End the loop at the last level.
+            if lv == 1 {
+                // We decremented the level previously, and given that our old level is one, the
+                // new level is zero.
+
+                log!(INTERNAL, "We're at the last level now.");
+
+                break;
+            }
+        }
+
+        // We're now at the bottom layer, in which we will iterate over to find the last element,
+        // below our needle.
+        // FIXME: These unwraps can be eliminated, find an approach which does not significantly
+        // increase CLOC of this function.
+        seek.node = iter.unwrap_node().iter().take_while(|x| x < block).last().unwrap();
+
+        seek.check();
+
+        // Everything have been initialized, including all the back look cells (i.e. every level
+        // have been visited).
+        seek
+    }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// Here is a rare Ferris to cheer you up.
+//          |
+//        \ _ /
+//      -= (_) =-
+//        /   \         _\/_ _\/_
+//          |           //o\ /o\\
+//   _____ _ __ __ _______|____|___________
+// =-=-_-__=_-= _=_=-=_,-'|_   |_  ()    ()
+//  =- _=-=- -_=-=_,-     "-   "-   \/\/\/
+//    =- =- -=.--"                  &_^^_&
+//                                  \    /
+// Don't share beach crab or it will lose
+// its value.

+ 317 - 0
src/bk/seek.rs

@@ -0,0 +1,317 @@
+struct Seek<'a> {
+    /// The last shortcut below our target for each level.
+    ///
+    /// This is used for insertions and other backtracking.
+    ///
+    /// The lower indexes are the denser layers.
+    ///
+    /// # Example
+    ///
+    /// Consider if we search for 8. Now, we move on until we overshoot. The node before the
+    /// overshot is a skip (marked with curly braces).
+    ///
+    /// ```
+    /// ...
+    /// 2      # ---------------------> {6} ---------------------> [9] -------------> NIL
+    /// 1      # ---------------------> [6] ---> {7} ------------> [9] -------------> NIL
+    /// 0      # ------------> [5] ---> [6] ---> {7} ------------> [9] ---> [10] ---> NIL
+    /// bottom # ---> [1] ---> [5] ---> [6] ---> [7] ---> [8] ---> [9] ---> [10] ---> NIL
+    /// ```
+    ///
+    /// So, the back look of this particular seek is `[6, 7, 7, ...]`.
+    // FIXME: Find a more rustic way than raw pointers.
+    back_look: [*mut Shortcuts; LEVELS.0],
+    /// A pointer to a pointer to the found node.
+    ///
+    /// This is the node equal to or less than the target. The two layers of pointers are there to
+    /// make it possible to modify the links and insert nodes before our target.
+    node: &'a mut Jar<Node>,
+}
+
+impl<'a> Seek<'a> {
+    /// Update the fat values of this seek.
+    ///
+    /// This will run over and update the fat values of shortcuts above some level with a new size.
+    #[inline]
+    fn update_fat(&mut self, size: block::Size, above: shortcut::Level) {
+        // Go from the densest layer and up, to update the fat node values.
+        for i in self.back_look.iter_mut().skip(above) {
+            if !i.update_fat(size) {
+                // Short-circuit for performance reasons.
+                break;
+            }
+        }
+    }
+
+    fn put(&mut self, block: Block, arena: &mut Arena<Node>) {
+        if self.node.block.merge_right(block).is_ok() {
+            // Merge suceeded:
+            //               [==block==]
+            //     [==self==]            [==rest==]
+            // is now:
+            //     [==self=============] [==rest==]
+
+            // Update the fat values.
+            self.update_fat(self.node.block.size(), 0);
+
+            // If our configuration now looks like:
+            //     [==self=============][==rest==]
+            // We need to maximize the former level, so we merge right.
+            if self.try_merge_right(arena).is_ok() { return; }
+
+        // Note that we do not merge our block to the seeked block from the left side. This is due
+        // to the seeked block being strictly less than our target, and thus we go one forward to
+        // the next block to see if it is mergable by its left side.
+        } else if self.node.next.and_then(|x| block.merge_right(x)).is_ok() {
+            // Merge suceeded:
+            //                [==block==]
+            //     [==self==]            [==right==]
+            // is now:
+            //     [==self==] [==right=============]
+
+            // Update the fat values.
+            self.update_fat(block.size(), 0);
+
+            // In case that our new configuration looks like:
+            //     [==self==][==right=============]
+            // We need to merge the former block right:
+            self.try_merge_right(arena);
+        } else {
+            self.insert_no_merge(block, arena);
+        }
+    }
+
+    fn try_merge_right(&mut self, arena: &mut Arena<Node>) {
+        if self.node.block.merge_right(self.node.next.block).is_ok() {
+            // We merged our node left. This means that the node is simply extended and an empty
+            // block will be left right to the node. As such the fat node's size is greater than or
+            // equal to the new, merged node's size. So we need not full reevaluation of the fat
+            // values, instead we can simply climb upwards and max the new size together.
+
+            // Consider the following configuration:
+            //     # -5-------------------> [7] -9--------------------> [6] -10-----------> NIL
+            //     # -5-------------------> [7] -7-> [9] -9-----------> [6] -10-----------> NIL
+            //     # -5----------> [1] -1-> [7] -7-> [9] -9-----------> [6] -6-> [10] -10-> NIL
+            //     # -5-> [5] -5-> [1] -1-> [7] -7-> [9] -9--> [8] -8-> [6] -6-> [10] -10-> NIL
+            // After the merge, our diagram looks like:
+            //     # -5-------------------> [7] -9--------------------> [6] -10-----------> NIL
+            //     # -5-------------------> [7] -7-> [17] -9----------> [6] -10-----------> NIL
+            //     # -5----------> [1] -1-> [7] -7-> [17] -9----------> [6] -6-> [10] -10-> NIL
+            //     # ---> [5] -5-> [1] -1-> [7] -7-> [17] -9-> [0] -0-> [6] -6-> [10] -10-> NIL
+            // But we do not allow empty blocks. So we need to a) remove the link b) update the fat
+            // values:
+            //     # -5-------------------> [7] -17-------------------> [6] -10-----------> NIL
+            //     # -5-------------------> [7] -7-> [17] -17---------> [6] -10-----------> NIL
+            //     # -5----------> [1] -1-> [7] -7-> [17] -17---------> [6] -6-> [10] -10-> NIL
+            //     # -5-> [5] -1-> [1] -1-> [7] -7-> [17] -17---------> [6] -6-> [10] -10-> NIL
+            // Fortunately, we know the back look of this particular seek, so we can simply iterate
+            // and set:
+            for (i, shortcut) in self.back_look.iter().zip(i.next.shortcuts) {
+                // Update the shortcut to skip over the next shortcut. Note that this statements
+                // makes it impossible to shortcut like in `insert`.
+                i.next = shortcut.next;
+                // Update the fat value to make sure it is greater or equal to the new block size.
+                // Note that we do not short-circuit -- on purpose -- due to the above statement
+                // being needed for correctness.
+                i.update_fat(self.node.block.size(), block::Size(0));
+
+                // TODO: Consider breaking this loop into two loops to avoid too many fat value
+                // updates.
+            }
+
+            // Finally, replace the useless node, and free it to the arena.
+            arena.free(mem::replace(self.node.next, self.node.next.unwrap().next)));
+        }
+    }
+
+    // Put a new shortcut starting at the current node at some level.
+    //
+    // This will simply insert a shortcut on level `lv`, spanning `self.node` to the end of the old
+    // shortcut, which is returned.
+    //
+    // The old shortcut is updated to point to `self.node`, but the fat value is kept as-is.
+    //
+    // The new shortcut's fat value will be set to the block's size, and recomputation is likely
+    // needed to update it.
+    fn update_shortcut(&mut self, lv: shortcut::Level) -> *mut Shortcut {
+        // Make the old shortcut point to `self.node`.
+        let old_next = mem::replace(&mut self.back_look[lv].next, Some(self.node));
+        mem::replace(&mut self.back_look[lv], Shortcut {
+            next: old_next,
+            fat: self.node.block.size(),
+        });
+    }
+
+    /// Insert a block (no merge) _after_ the found node.
+    ///
+    /// This will simply insert (place) the node after our found node, without merges. The fat
+    /// values are updated.
+    fn insert_no_merge(&mut self, block: Block, arena: &mut Arena<Node>) {
+        take::replace_with(self, |mut seek| {
+            // Make sure that there are no adjacent blocks.
+            debug_assert!(!self.node.left_to(&block), "Inserting left-adjacent block without \
+                          merge.");
+            debug_assert!(!self.node.next.map_or(false, |x| x.left_to(&block)), "Inserting \
+                          right-adjacent block without merge.");
+            // Check that we're inserting at a fitting position, such that the list is kept sorted.
+            debug_assert!(self.node.block < block, "Inserting at a wrong position.");
+
+            // Put the old node behind the new node holding block.
+            let mut new_node = arena.alloc(Node {
+                block: block,
+                // Place-holder.
+                shortcuts: Default::default(),
+                next: None,
+            });
+
+            // Generate the maximum level of the new node's shortcuts.
+            let height = shortcut::Level::generate();
+
+            // Insert the new node up front, shifting the rest forward.
+            take::replace_with(seek.node, |node| {
+                new_node.next = Some(node);
+                new_node
+            });
+
+            // If we actually have a bottom layer (i.e. the generated level is higher than zero),
+            // we obviously need to update its fat values based on the main list.
+            // FIXME: This code is copied from the loop below. Find a way to avoid repeating.
+            if height > shortcut::Level(0) {
+                // Place the node into the bottom shortcut.
+                self.update_shortcut(shortcut::Level(0));
+
+                // For details how this works, see the loop below. This is really just taken from
+                // the iteration from that to reflect the special structure of the block list.
+
+                // Calculate the fat value of the bottom layer.
+                let new_fat = seek.node.calculate_fat_value_bottom();
+
+                let skip = &mut seek.back_look[0];
+                if new_fat == skip.fat {
+                    if let Some(next) = skip.next {
+                        next.fat = next.calculate_fat_value_bottom();
+                    }
+                } else {
+                    skip.node.shortcuts[0].update_fat(mem::replace(&mut skip.fat, new_fat));
+                }
+            }
+
+            // Place new shortcuts up to this level.
+            for lv in shortcut::Level(1)..height {
+                // Place the node inbetween the shortcuts.
+                seek.place_node_inbetween(&mut seek.node, lv);
+
+                // The configuration (at level `lv`) should now look like:
+                //     [seek.node] --> [old self.node] --> [old shortcut]
+
+                // Since we inserted a new shortcut here, we might have invalidated the old fat
+                // value, so we need to recompute the fat value. Fortunately, since we go from
+                // densest to opaquer layer, we can base the fat value on the values of the
+                // previous layer.
+
+                // An example state could look like this: Assume we go from this configuration:
+                //     [a] -y----------> [b] ---> ...
+                //     [a] -x----------> [b] ---> ...
+                //     ...
+                // To this:
+                //     [a] -y'---------> [b] ---> ...
+                //     [a] -p-> [n] -q-> [b] ---> ...
+                //     ...
+                // Here, you cannot express _p_ and _q_ in terms  of _x_ and _y_. Instead, we need
+                // to compute them from the layer below.
+                let new_fat = seek.node.calculate_fat_value_non_bottom(lv);
+
+                // You have been visitied by the silly ferris.
+                //      ()    ()
+                //       \/\/\/
+                //       &_^^_&
+                //       \    /
+                // Fix all bugs in 0.9345 seconds, or you will be stuck doing premature
+                // optimizations forever.
+
+                // Avoid multiple bound checks.
+                let skip = &mut seek.back_look[lv];
+                // The shortcut behind the updated one might be invalidated as well. We use a nifty
+                // trick: If the fat node is not present on one part of the split (defined by the
+                // newly inserted node), it must fall on the other. So, we can shortcut and safely
+                // skip computation of the second part half of the time.
+                if new_fat == skip.fat {
+                    if let Some(next) = skip.next {
+                        // The fat value was left unchanged. This means that we need to recompute the
+                        // next segment's fat value.
+                        next.fat = next.calculate_fat_value_non_bottom(lv);
+                    }
+
+                    // Since it was unchanged, there is no need for setting the value to what it
+                    // already is!
+                } else {
+                    // The first segment did not contain the fat node! This means that we know a
+                    // priori that the second segment contains the old fat node, i.e. has either
+                    // the same fat value or the updated node is itself the fat node. So, we
+                    // replace the new fat value and update the next segment with the old one.  As
+                    // an example, suppose the configuration looked like:
+                    //     [a] -f----------> [b]
+                    // And we inserted a new node _x_:
+                    //     [a] -g-> [x] -h-> [b]
+                    // Since the fat node (size _f_) couldn't be found on the left side (_g_) of
+                    // _x_, it must be on the right side (_h ≥ f_). It might not be equal to it,
+                    // because the size of _x_ could be greater than _f_, so we take the maximal of
+                    // _x_ and _f_ and assigns that to _h_. This way we avoid having to iterate
+                    // over all the nodes between _x_ and _b_.
+                    skip.next.unwrap().shortcuts[lv].update_fat(mem::replace(&mut skip.fat, new_fat), seek.node.block.size()));
+                }
+            }
+
+            // The levels above the inserted shortcuts need to get there fat value updated, since a
+            // new node was inserted below. Since we only inserted (i.e. added a potentially new
+            // fat node), we simply need to max the old (unupdated) fat values with the new block's
+            // size.
+            seek.update_fat(seek.node.block.size(), height);
+
+            seek.node.check();
+
+            seek
+        });
+
+        self.check();
+    }
+
+    fn remove(&mut self) -> Jar<Node> {
+        unimplemented!();
+    }
+
+    /// Check this seek.
+    ///
+    /// This is NOOP in release mode.
+    fn check(&self) {
+        if cfg!(debug_assertions) {
+            // Check the nodes.
+            for i in self.node.iter() {
+                i.check();
+            }
+
+            // Check the back look.
+            let mut iter = self.back_look().peekable();
+            let mut n = 0;
+            loop {
+                let cur = iter.next();
+                let next = iter.peek();
+
+                if let (Some(cur), Some(next)) = (cur, next) {
+                    // The fat value satisfy the heap property, and thus must be ordered as such.
+                    assert!(cur.fat <= next.fat, "The {}'th back look entry has a fat value higher \
+                            than its parent level, which ought to be less dense.", n);
+                    // The next layer should be less dense, as such, the pointer is lower than the
+                    // current one.
+                    assert!(cur.next >= next.next, "The {}'th back look entry's next-node pointer \
+                            is lower than the parent level's pointer, despite that it ought to be \
+                            denser.", n);
+
+                    n += 1;
+                } else {
+                    break;
+                }
+            }
+        }
+    }
+}

+ 132 - 0
src/bk/shortcut.rs

@@ -0,0 +1,132 @@
+use block;
+
+// TODO: Tweak.
+// TODO: Move to shim.
+const LEVELS: Level = Level(8);
+
+usize_newtype!(pub Level);
+
+impl Level {
+    /// Generate a skip list level.
+    ///
+    /// This is equivalent to making `LEVELS` coinflips and count until you get heads and saturate to
+    /// `LEVELS` if none is made.
+    ///
+    /// We make use of bit hacks to speed this process up such that only one random state update is
+    /// needed.
+    #[inline]
+    fn generate_level() -> Level {
+        // Naturally, the ffz conforms to our wanted probability distribution, $p(x) = 2^{-x}$a. We
+        // apply a bit mask to saturate when the ffz is greater than `LEVELS`.
+        (random::get() & (1 << LEVELS - 1)).trailing_zeros()
+    }
+
+    #[inline]
+    fn max() -> Level {
+        LEVELS - Level(1)
+    }
+}
+
+impl Into<usize> for Level {
+    fn into(self) -> usize {
+        self.0
+    }
+}
+
+#[inline]
+fn level_iter() -> impl Iterator<Item = Level> {
+    Level(0)..Level::max()
+}
+
+#[derive(Default)]
+struct Shortcut {
+    next: Option<Pointer<Node>>,
+    fat: block::Size,
+}
+
+impl Shortcut {
+    #[inline]
+    fn is_null(&self) -> bool {
+        self.next.is_null()
+    }
+
+    /// Update the fat value in case the new node is bigger than the current fat node.
+    ///
+    /// When inserting it is important for us to maintain the invariants. In this case, keeping
+    /// track of the size of the biggest node skipped. When a new node is inserted, this value
+    /// should naturally reflect that. If the new node's size is in fact greater than the fat
+    /// value, the fat value will be updated.
+    ///
+    /// # Short-circuiting
+    ///
+    /// The returned value indicates if the caller should continue propagating new fat value up.
+    /// This is based on the observation that updating the fat value is similar to heap insertion.
+    ///
+    /// Consider insertion a block of size 4:
+    ///     [6] -6-------------------> ...
+    ///     [6] -6-------------------> ...
+    ///     [6] -6--------> [2] -2---> ...
+    ///     [6] -6--------> [4] -4---> ...
+    /// Clearly, all the unchanged fat values of the two highest levels are correct, but the third
+    /// level's value following [2] is not. So we can shortcircuit when we get to the second last
+    /// level, due to the fact that the tree of the shortcut's fat values satisfy the heap
+    /// property:
+    ///
+    ///       6
+    ///       |
+    ///       6
+    ///      / \
+    ///     6   |
+    ///         4
+    ///         |
+    ///         2
+    /// Let _A_ be a node with set of children _C_, then_ A = max(C)_. As such, if I start in the
+    /// bottom and iterate upwards, as soon as the value stays unchanged, the rest of the values
+    /// won't change either.
+    #[inline]
+    fn update_fat(&mut self, new_node: block::Size) -> bool {
+        let res = self.fat <= self.node.block.size();
+
+        // We max them with the new block size to ensure they're properly set.
+        self.fat = cmp::max(i.fat, self.node.block.size());
+
+        res
+    }
+}
+
+struct ShortcutIter<'a> {
+    lv: Level,
+    shortcut: Option<&'a Shortcut>,
+}
+
+impl<'a> ShortcutIter<'a> {
+    /// Decrement the shortcut level of this iterator and return the old level.
+    ///
+    /// This will make the iterator skip approximately half of the elements of the previous state
+    /// of the iterator.
+    #[inline]
+    fn decrement_level(&mut self) -> Level {
+        let lv = self.lv;
+        self.lv -= Level(1);
+        lv
+    }
+
+    /// Unwrap the inner node (of the shortcut that the iterator is currently on).
+    ///
+    /// # Panics
+    ///
+    /// This will panic if the iterator is over (i.e. no node is left)
+    #[inline]
+    fn unwrap_node(self) -> &Node {
+        self.shortcut.unwrap().node
+    }
+}
+
+impl<'a> Iterator for ShortcutIter<'a> {
+    type Item = &'a Shortcut;
+
+    fn next(&mut self) -> &'a mut Shortcut {
+        // Replace `self.shortcut` by the next shortcut, and return the old value.
+        mem::replace(&mut self.shortcut, self.shortcut.map(|x| x.shortcut[self.lv].get()))
+    }
+}

+ 35 - 27
src/block.rs

@@ -9,6 +9,10 @@ use prelude::*;
 
 use core::{ptr, cmp, mem, fmt};
 
+use ptr;
+
+usize_newtype!(pub Size);
+
 /// A contiguous memory block.
 ///
 /// This provides a number of guarantees,
@@ -25,10 +29,11 @@ use core::{ptr, cmp, mem, fmt};
 ///
 /// Accessing it through an immutable reference does not break these guarantees. That is, you are
 /// not able to read/mutate without acquiring a _mutable_ reference.
-#[must_use]
+#[must_use = "`Block` represents some owned memory, not using it will likely result in memory \
+              leaks."]
 pub struct Block {
     /// The size of this block, in bytes.
-    size: usize,
+    size: Size,
     /// The pointer to the start of this block.
     ptr: Pointer<u8>,
 }
@@ -36,7 +41,7 @@ pub struct Block {
 impl Block {
     /// Construct a block from its raw parts (pointer and size).
     #[inline]
-    pub unsafe fn from_raw_parts(ptr: Pointer<u8>, size: usize) -> Block {
+    pub unsafe fn from_raw_parts(ptr: Pointer<u8>, size: Size) -> Block {
         Block {
             size: size,
             ptr: ptr,
@@ -53,13 +58,13 @@ impl Block {
         }
     }
 
-    /// Create an empty block representing the left edge of this block
+    /// Create an empty block representing the left edge of this block.
     #[inline]
     pub fn empty_left(&self) -> Block {
         Block::empty(self.ptr.clone())
     }
 
-    /// Create an empty block representing the right edge of this block
+    /// Create an empty block representing the right edge of this block.
     #[inline]
     #[allow(cast_possible_wrap)]
     pub fn empty_right(&self) -> Block {
@@ -84,9 +89,7 @@ impl Block {
     /// If you merge with a zero sized block, it will succeed, even if they are not adjacent.
     #[inline]
     pub fn merge_right(&mut self, block: &mut Block) -> Result<(), ()> {
-        if block.is_empty() {
-            Ok(())
-        } else if self.left_to(block) {
+        if self.left_to(block) {
             // Since the end of `block` is bounded by the address space, adding them cannot
             // overflow.
             self.size += block.pop().size;
@@ -103,14 +106,14 @@ impl Block {
     }
 
     /// Get the size of the block.
-    pub fn size(&self) -> usize {
+    pub fn size(&self) -> Size {
         self.size
     }
 
     /// Is this block aligned to `align`?
     #[inline]
-    pub fn aligned_to(&self, align: usize) -> bool {
-        *self.ptr as usize % align == 0
+    pub fn aligned_to(&self, align: ptr::Align) -> bool {
+        self.ptr.aligned_to(align)
     }
 
     /// memcpy the block to another pointer.
@@ -161,6 +164,12 @@ impl Block {
     /// Is this block placed left to the given other block?
     #[inline]
     pub fn left_to(&self, to: &Block) -> bool {
+        // Warn about potential confusion of `self` and `to` and other similar bugs.
+        if cfg!(debug_assertions) && self >= to {
+            log!(WARNING, "{:?} is not lower than {:?}. Are you sure this `left_to()` is correctly \
+                 used?", self, to);
+        }
+
         // This won't overflow due to the end being bounded by the address space.
         self.size + *self.ptr as usize == *to.ptr as usize
     }
@@ -172,7 +181,7 @@ impl Block {
     /// Panics if `pos` is out of bound.
     #[inline]
     #[allow(cast_possible_wrap)]
-    pub fn split(self, pos: usize) -> (Block, Block) {
+    pub fn split(self, pos: Size) -> (Block, Block) {
         assert!(pos <= self.size, "Split {} out of bound (size is {})!", pos, self.size);
 
         (
@@ -198,17 +207,17 @@ impl Block {
     /// Returns an `None` holding the intact block if `align` is out of bounds.
     #[inline]
     #[allow(cast_possible_wrap)]
-    pub fn align(&mut self, align: usize) -> Option<(Block, Block)> {
-        // Logging.
+    pub fn align(&mut self, align: ptr::Align) -> Option<(Block, Block)> {
         log!(INTERNAL, "Padding {:?} to align {}", self, align);
 
-        // TODO: This functions suffers from external fragmentation. Leaving bigger segments might
+        // FIXME: This functions suffers from external fragmentation. Leaving bigger segments might
         // increase performance.
 
         // Calculate the aligner, which defines the smallest size required as precursor to align
         // the block to `align`.
-        let aligner = (align - *self.ptr as usize % align) % align;
-        //                                                 ^^^^^^^^
+        // TODO: This can be reduced.
+        let aligner = (align.into_usize() - *self.ptr as usize % align.into_usize()) % align.into_usize();
+        //                                                       ^^^^^^^^^^^^^^^^^^
         // To avoid wasting space on the case where the block is already aligned, we calculate it
         // modulo `align`.
 
@@ -219,7 +228,7 @@ impl Block {
 
             Some((
                 Block {
-                    size: aligner,
+                    size: Size(aligner),
                     ptr: old.ptr.clone(),
                 },
                 Block {
@@ -234,7 +243,6 @@ impl Block {
                 }
             ))
         } else {
-            // Logging.
             log!(INTERNAL, "Unable to align block.");
 
             None
@@ -248,7 +256,7 @@ impl Block {
     #[inline]
     pub fn mark_free(self) -> Block {
         #[cfg(feature = "debugger")]
-        ::shim::debug::mark_free(*self.ptr as *const u8, self.size);
+        ::shim::debug::mark_free(*self.ptr, self.size);
 
         self
     }
@@ -259,7 +267,7 @@ impl Block {
     #[inline]
     pub fn mark_uninitialized(self) -> Block {
         #[cfg(feature = "debugger")]
-        ::shim::debug::mark_unintialized(*self.ptr as *const u8, self.size);
+        ::shim::debug::mark_unintialized(*self.ptr, self.size);
 
         self
     }
@@ -310,7 +318,7 @@ mod test {
     fn test_array() {
         let arr = b"Lorem ipsum dolor sit amet";
         let block = unsafe {
-            Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
+            Block::from_raw_parts(Pointer::new(arr.as_ptr()), arr.len())
         };
 
         // Test split.
@@ -330,7 +338,7 @@ mod test {
     fn test_merge() {
         let arr = b"Lorem ipsum dolor sit amet";
         let block = unsafe {
-            Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
+            Block::from_raw_parts(Pointer::new(arr.as_ptr()), arr.len())
         };
 
         let (mut lorem, mut rest) = block.split(5);
@@ -346,7 +354,7 @@ mod test {
     fn test_oob() {
         let arr = b"lorem";
         let block = unsafe {
-            Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
+            Block::from_raw_parts(Pointer::new(arr.as_ptr()), arr.len())
         };
 
         // Test OOB.
@@ -358,7 +366,7 @@ mod test {
         let mut arr = [0u8, 2, 0, 0, 255, 255];
 
         let block = unsafe {
-            Block::from_raw_parts(Pointer::new(&mut arr[0] as *mut u8), 6)
+            Block::from_raw_parts(Pointer::new(&mut arr[0]), 6)
         };
 
         let (a, mut b) = block.split(2);
@@ -371,12 +379,12 @@ mod test {
     fn test_empty_lr() {
         let arr = b"Lorem ipsum dolor sit amet";
         let block = unsafe {
-            Block::from_raw_parts(Pointer::new(arr.as_ptr() as *mut u8), arr.len())
+            Block::from_raw_parts(Pointer::new(arr.as_ptr()), arr.len())
         };
 
         assert!(block.empty_left().is_empty());
         assert!(block.empty_right().is_empty());
-        assert_eq!(*Pointer::from(block.empty_left()) as *const u8, arr.as_ptr());
+        assert_eq!(*Pointer::from(block.empty_left()), arr.as_ptr());
         assert_eq!(block.empty_right(), block.split(arr.len()).1);
     }
 }

+ 0 - 956
src/bookkeeper.rs

@@ -1,956 +0,0 @@
-//! Memory bookkeeping.
-
-use prelude::*;
-
-use core::ops::Range;
-use core::{ptr, mem, ops};
-
-use shim::config;
-
-/// Elements required _more_ than the length as capacity.
-///
-/// This represents how many elements that are needed to conduct a `reserve` without the
-/// stack overflowing, plus one (representing the new element):
-///
-/// 1. Aligner.
-/// 2. Excessive space.
-/// 3. The old buffer.
-/// 4. The pushed or inserted block.
-///
-/// See assumption 4.
-pub const EXTRA_ELEMENTS: usize = 4;
-
-#[cfg(feature = "alloc_id")]
-use core::sync::atomic::{self, AtomicUsize};
-/// The bookkeeper ID count.
-///
-/// This is atomically incremented whenever a new `Bookkeeper` is created.
-#[cfg(feature = "alloc_id")]
-static BOOKKEEPER_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);
-
-/// The memory bookkeeper.
-///
-/// This stores data about the state of the allocator, and in particular, the free memory.
-///
-/// The actual functionality is provided by [`Allocator`](./trait.Allocator.html).
-pub struct Bookkeeper {
-    /// The internal block pool.
-    ///
-    /// Entries in the block pool can be "empty", meaning that you can overwrite the entry without
-    /// breaking consistency.
-    ///
-    /// # Assumptions
-    ///
-    /// Certain assumptions are made:
-    ///
-    /// 1. The list is always sorted with respect to the block's pointers.
-    /// 2. No two consecutive or empty block delimited blocks are adjacent, except if the right
-    ///    block is empty.
-    /// 3. There are no trailing empty blocks.
-    /// 4. The capacity is always `EXTRA_ELEMENTS` blocks more than the length (this is due to
-    ///    reallocation pushing at maximum two elements, so we reserve two or more extra to allow
-    ///    pushing one additional element without unbounded recursion).
-    ///
-    /// These are **not** invariants: If these assumpptions are not held, it will simply act strange
-    /// (e.g. logic bugs), but not memory unsafety.
-    pool: Vec<Block>,
-    /// The total number of bytes in the pool.
-    total_bytes: usize,
-    /// Is this bookkeeper currently reserving?
-    ///
-    /// This is used to avoid unbounded metacircular reallocation (reservation).
-    ///
-    // TODO: Find a replacement for this "hack".
-    reserving: bool,
-    /// The allocator ID.
-    ///
-    /// This is simply to be able to distinguish allocators in the locks.
-    #[cfg(feature = "alloc_id")]
-    id: usize,
-}
-
-#[allow(len_without_is_empty)]
-impl Bookkeeper {
-    /// Create a new bookkeeper with some initial vector.
-    pub fn new(vec: Vec<Block>) -> Bookkeeper {
-        // Make sure the assumptions are satisfied.
-        debug_assert!(vec.capacity() >= EXTRA_ELEMENTS, "Not enough initial capacity of the vector.");
-        debug_assert!(vec.is_empty(), "Initial vector isn't empty.");
-
-        // TODO: When added use expr field attributes.
-        #[cfg(feature = "alloc_id")]
-        let res = Bookkeeper {
-            pool: vec,
-            total_bytes: 0,
-            reserving: false,
-            // Increment the ID counter to get a brand new ID.
-            id: BOOKKEEPER_ID_COUNTER.fetch_add(1, atomic::Ordering::SeqCst),
-        };
-        #[cfg(not(feature = "alloc_id"))]
-        let res = Bookkeeper {
-            pool: vec,
-            total_bytes: 0,
-            reserving: false,
-        };
-
-        bk_log!(res, "Bookkeeper created.");
-        res.check();
-
-        res
-    }
-
-    /// Perform a binary search to find the appropriate place where the block can be insert or is
-    /// located.
-    ///
-    /// It is guaranteed that no block left to the returned value, satisfy the above condition.
-    #[inline]
-    fn find(&mut self, block: &Block) -> usize {
-        // Logging.
-        bk_log!(self, "Searching (exact) for {:?}.", block);
-
-        let ind = match self.pool.binary_search(block) {
-            Ok(x) | Err(x) => x,
-        };
-        let len = self.pool.len();
-
-        // Move left.
-        ind - self.pool.iter_mut()
-            .rev()
-            .skip(len - ind)
-            .take_while(|x| x.is_empty())
-            .count()
-    }
-
-    /// Perform a binary search to find the appropriate bound where the block can be insert or is
-    /// located.
-    ///
-    /// It is guaranteed that no block left to the returned value, satisfy the above condition.
-    #[inline]
-    fn find_bound(&mut self, block: &Block) -> Range<usize> {
-        // Logging.
-        bk_log!(self, "Searching (bounds) for {:?}.", block);
-
-        let mut left_ind = match self.pool.binary_search(block) {
-            Ok(x) | Err(x) => x,
-        };
-
-        let len = self.pool.len();
-
-        // Move left.
-        left_ind -= self.pool.iter_mut()
-            .rev()
-            .skip(len - left_ind)
-            .take_while(|x| x.is_empty())
-            .count();
-
-        let mut right_ind = match self.pool.binary_search(&block.empty_right()) {
-            Ok(x) | Err(x) => x,
-        };
-
-        // Move right.
-        right_ind += self.pool.iter()
-            .skip(right_ind)
-            .take_while(|x| x.is_empty())
-            .count();
-
-        left_ind..right_ind
-    }
-
-    /// Go over every block in the allocator and call some function.
-    ///
-    /// Technically, this could be done through an iterator, but this, more unidiomatic, way is
-    /// slightly faster in some cases.
-    pub fn for_each<F: FnMut(Block)>(mut self, mut f: F) {
-        // Logging.
-        bk_log!(self, "Iterating over the blocks of the bookkeeper...");
-
-        // Run over all the blocks in the pool.
-        for i in self.pool.pop_iter() {
-            f(i);
-        }
-
-        // Take the block holding the pool.
-        f(Block::from(self.pool));
-    }
-
-    /// Pop the top block from the pool.
-    pub fn pop(&mut self) -> Option<Block> {
-        self.pool.pop().map(|res| {
-            // Update the byte count.
-            self.total_bytes -= res.size();
-
-            // Check stuff, just in case.
-            self.check();
-
-            res
-        })
-    }
-
-    /// Get the length of the pool.
-    pub fn len(&self) -> usize {
-        self.pool.len()
-    }
-
-    /// Get the total bytes of memory in the pool.
-    pub fn total_bytes(&self) -> usize {
-        self.total_bytes
-    }
-
-    /// Perform consistency checks.
-    ///
-    /// This will check for the following conditions:
-    ///
-    /// 1. The list is sorted.
-    /// 2. No blocks are adjacent.
-    ///
-    /// This is NOOP in release mode.
-    fn check(&self) {
-        if cfg!(debug_assertions) {
-            // Logging.
-            bk_log!(self, "Checking...");
-
-            // The total number of bytes.
-            let mut total_bytes = 0;
-            // Reverse iterator over the blocks.
-            let mut it = self.pool.iter().enumerate().rev();
-
-            // Check that the capacity is large enough.
-            assert!(self.reserving || self.pool.len() + EXTRA_ELEMENTS <= self.pool.capacity(),
-                    "The capacity should be at least {} more than the length of the pool.",
-                    EXTRA_ELEMENTS);
-
-            if let Some((_, x)) = it.next() {
-                // Make sure there are no leading empty blocks.
-                assert!(!x.is_empty(), "The leading block is empty.");
-
-                total_bytes += x.size();
-
-                let mut next = x;
-                for (n, i) in it {
-                    total_bytes += i.size();
-
-                    // Check if sorted.
-                    assert!(next >= i, "The block pool is not sorted at index, {} ({:?} < {:?}).",
-                            n, next, i);
-                    // Make sure no blocks are adjacent.
-                    assert!(!i.left_to(next) || i.is_empty(), "Adjacent blocks at index, {} ({:?} and \
-                            {:?})", n, i, next);
-                    // Make sure an empty block has the same address as its right neighbor.
-                    assert!(!i.is_empty() || i == next, "Empty block not adjacent to right neighbor \
-                            at index {} ({:?} and {:?})", n, i, next);
-
-                    // Set the variable tracking the previous block.
-                    next = i;
-                }
-
-                // Check for trailing empty blocks.
-                assert!(!self.pool.last().unwrap().is_empty(), "Trailing empty blocks.");
-            }
-
-            // Make sure the sum is maintained properly.
-            assert!(total_bytes == self.total_bytes, "The sum is not equal to the 'total_bytes' \
-                    field: {} ≠ {}.", total_bytes, self.total_bytes);
-        }
-    }
-}
-
-/// An allocator.
-///
-/// This provides the functionality of the memory bookkeeper, requiring only provision of two
-/// methods, defining the "breaker" (fresh allocator). The core functionality is provided by
-/// default methods, which aren't generally made to be overwritten.
-///
-/// The reason why these methods aren't implemented directly on the bookkeeper is the distinction
-/// between different forms of allocators (global, local, and so on). Any newtype of
-/// [`Bookkeeper`](./struct.Bookkeeper.html).
-///
-/// # Guarantees vs. assumptions
-///
-/// Please note that whenever a guarantee is mentioned, it relies on that the all the methods
-/// overwritten are upholding the guarantees specified in the documentation.
-pub trait Allocator: ops::DerefMut<Target = Bookkeeper> {
-    /// Allocate _fresh_ space.
-    ///
-    /// "Fresh" means that the space is allocated through some breaker (be it SBRK or the global
-    /// allocator).
-    ///
-    /// The returned pointer is assumed to be aligned to `align`. If this is not held, all future
-    /// guarantees are invalid.
-    ///
-    /// # Assumptions
-    ///
-    /// This is assumed to not modify the order. If some block `b` is associated with index `i`
-    /// prior to call of this function, it should be too after it.
-    fn alloc_fresh(&mut self, size: usize, align: usize) -> Block;
-
-    /// Called right before new memory is added to the pool.
-    fn on_new_memory(&mut self) {}
-
-    /// Allocate a chunk of memory.
-    ///
-    /// This function takes a size and an alignment. From these a fitting block is found, to which
-    /// a pointer is returned. The block returned is guaranteed to be aligned to `align`.
-    ///
-    /// # Example
-    ///
-    /// We start with our initial segment.
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I---------------------------------I
-    /// B
-    /// l
-    /// k
-    /// s
-    /// ```
-    ///
-    /// We then split it at the aligner, which is used for making sure that
-    /// the pointer is aligned properly.
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I------I
-    /// B   ^    I--------------------------I
-    /// l  al
-    /// k
-    /// s
-    /// ```
-    ///
-    /// We then use the remaining block, but leave the excessive space.
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I------I
-    /// B                           I--------I
-    /// l        \_________________/
-    /// k        our allocated block.
-    /// s
-    /// ```
-    ///
-    /// A block representing the marked area is then returned.
-    fn alloc(&mut self, size: usize, align: usize) -> Block {
-        // Logging.
-        bk_log!(self, "Allocating {} bytes with alignment {}.", size, align);
-
-        if let Some((n, b)) = self.pool.iter_mut().enumerate().filter_map(|(n, i)| {
-            if i.size() >= size {
-                // Try to split at the aligner.
-                i.align(align).and_then(|(mut a, mut b)| {
-                    if b.size() >= size {
-                        // Override the old block.
-                        *i = a;
-                        Some((n, b))
-                    } else {
-                        // Put the split block back together and place it back in its spot.
-                        a.merge_right(&mut b).expect("Unable to merge block right.");
-                        *i = a;
-                        None
-                    }
-                })
-            } else {
-                None
-            }
-        }).next() {
-            // Update the pool byte count.
-            self.total_bytes -= b.size();
-
-            if self.pool[n].is_empty() {
-                // For empty alignment invariant.
-                let _ = self.remove_at(n);
-            }
-
-            // Split and mark the block uninitialized to the debugger.
-            let (res, excessive) = b.mark_uninitialized().split(size);
-
-            // There are many corner cases that make knowing where to insert it difficult
-            // so we search instead.
-            self.free(excessive);
-
-            // Check consistency.
-            self.check();
-            debug_assert!(res.aligned_to(align), "Alignment failed.");
-            debug_assert!(res.size() == size, "Requested space does not match with the returned \
-                          block.");
-
-            res
-        } else {
-            // No fitting block found. Allocate a new block.
-            self.alloc_external(size, align)
-        }
-    }
-
-    /// Free a memory block.
-    ///
-    /// After this have been called, no guarantees are made about the passed pointer. If it want
-    /// to, it could begin shooting laser beams.
-    ///
-    /// Freeing an invalid block will drop all future guarantees about this bookkeeper.
-    ///
-    /// # Example
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I------I
-    /// B                                  I--------I
-    /// l        \_________________/
-    /// k     the used block we want to deallocate.
-    /// s
-    /// ```
-    ///
-    /// If the blocks are adjacent, we merge them:
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I------I
-    /// B        I-----------------I
-    /// l                                  I--------I
-    /// k
-    /// s
-    /// ```
-    ///
-    /// This gives us:
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I------------------------I
-    /// B                                  I--------I
-    /// l
-    /// k
-    /// s
-    /// ```
-    ///
-    /// And we're done. If it cannot be done, we insert the block, while keeping the list sorted.
-    /// See [`insert`](#method.insert) for details.
-    #[inline]
-    fn free(&mut self, block: Block) {
-        // Just logging for the unlucky people debugging this shit. No problem.
-        bk_log!(self, "Freeing {:?}...", block);
-
-        // Binary search for the block.
-        let bound = self.find_bound(&block);
-
-        // Free the given block.
-        self.free_bound(bound, block);
-    }
-
-    /// Reallocate memory.
-    ///
-    /// If necessary (inplace reallocation is not possible or feasible) it will allocate a new
-    /// buffer, fill it with the contents of the old buffer, and deallocate the replaced buffer.
-    ///
-    /// The following guarantees are made:
-    ///
-    /// 1. The returned block is valid and aligned to `align`.
-    /// 2. The returned block contains the same data byte-for-byte as the original buffer.
-    ///
-    /// The data will be truncated if `new_size` is smaller than `block`'s size.
-    ///
-    /// # Example
-    ///
-    /// We will first try to perform an in-place reallocation, and if that fails, we will use
-    /// memmove.
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I------I
-    /// B \~~~~~~~~~~~~~~~~~~~~~/
-    /// l     needed
-    /// k
-    /// s
-    /// ```
-    ///
-    /// We simply find the block next to our initial block. If this block is free and have
-    /// sufficient size, we will simply merge it into our initial block, and leave the excessive
-    /// space as free. If these conditions are not met, we have to allocate a new list, and then
-    /// deallocate the old one, after which we use memmove to copy the data over to the newly
-    /// allocated list.
-    fn realloc(&mut self, block: Block, new_size: usize, align: usize) -> Block {
-        // Find the index bound.
-        let ind = self.find_bound(&block);
-
-        // Logging.
-        bk_log!(self;ind, "Reallocating {:?} to size {} with align {}...", block, new_size, align);
-
-        // Try to do an inplace reallocation.
-        match self.realloc_inplace_bound(ind, block, new_size) {
-            Ok(block) => block,
-            Err(block) => {
-                // Reallocation cannot be done inplace.
-
-                // Allocate a new block with the same size.
-                let mut res = self.alloc(new_size, align);
-
-                // Copy the old data to the new location.
-                block.copy_to(&mut res);
-
-                // Free the old block.
-                // Allocation may have moved insertion so we search again.
-                self.free(block);
-
-                // Check consistency.
-                self.check();
-                debug_assert!(res.aligned_to(align), "Alignment failed.");
-                debug_assert!(res.size() >= new_size, "Requested space does not match with the \
-                              returned block.");
-
-                res
-            },
-        }
-    }
-
-    /// Extend/shrink the buffer inplace.
-    ///
-    /// This will try to extend the buffer without copying, if the new size is larger than the old
-    /// one. If not, truncate the block and place it back to the pool.
-    ///
-    /// On failure, return `Err(Block)` with the old _intact_ block. Shrinking cannot fail.
-    ///
-    /// This shouldn't be used when the index of insertion is known, since this performs an binary
-    /// search to find the blocks index. When you know the index use
-    /// [`realloc_inplace_bound`](#method.realloc_inplace_bound.html).
-    #[inline]
-    fn realloc_inplace(&mut self, block: Block, new_size: usize) -> Result<Block, Block> {
-        // Logging.
-        bk_log!(self, "Reallocating {:?} inplace to {}...", block, new_size);
-
-        // Find the bounds of given block.
-        let bound = self.find_bound(&block);
-
-        // Go for it!
-        let res = self.realloc_inplace_bound(bound, block, new_size);
-
-        // Check consistency.
-        debug_assert!(res.as_ref().ok().map_or(true, |x| x.size() == new_size), "Requested space \
-                      does not match with the returned block.");
-
-        res
-    }
-
-    /// Reallocate a block on a know index bound inplace.
-    ///
-    /// See [`realloc_inplace`](#method.realloc_inplace.html) for more information.
-    fn realloc_inplace_bound(&mut self, ind: Range<usize>, mut block: Block, new_size: usize) -> Result<Block, Block> {
-        // Logging.
-        bk_log!(self;ind, "Try inplace reallocating {:?} to size {}.", block, new_size);
-
-        /// Assertions...
-        debug_assert!(self.find(&block) == ind.start, "Block is not inserted at the appropriate \
-                      index.");
-
-        if new_size <= block.size() {
-            // Shrink the block.
-            bk_log!(self;ind, "Shrinking {:?}.", block);
-
-            // Split the block in two segments, the main segment and the excessive segment.
-            let (block, excessive) = block.split(new_size);
-            // Free the excessive segment.
-            self.free_bound(ind, excessive);
-
-            // Make some assertions to avoid dumb bugs.
-            debug_assert!(block.size() == new_size, "Block wasn't shrinked properly.");
-
-            // Run a consistency check.
-            self.check();
-
-            return Ok(block);
-
-            // We check if `ind` is the end of the array.
-        } else {
-            let mut mergable = false;
-            if let Some(entry) = self.pool.get_mut(ind.end) {
-                mergable = entry.size() + block.size() >= new_size && block.left_to(entry);
-            }
-            // Note that we are sure that no segments in the array are adjacent (unless they have size
-            // 0). This way we know that we will, at maximum, need one and only one block for extending
-            // the current block.
-            if mergable {
-                // Logging...
-                bk_log!(self;ind, "Merging {:?} to the right.", block);
-
-                // We'll merge it with the block at the end of the range.
-                block.merge_right(&mut self.remove_at(ind.end))
-                    .expect("Unable to merge block right, to the end of the range.");
-                // Merge succeeded.
-
-                // Place the excessive block back.
-                let (res, excessive) = block.split(new_size);
-                // Remove_at may have shortened the vector.
-                if ind.start == self.pool.len() {
-                    self.push(excessive);
-                } else if !excessive.is_empty() {
-                    self.pool[ind.start] = excessive;
-                }
-                // Block will still not be adjacent, due to `excessive` being guaranteed to not be
-                // adjacent to the next block.
-
-                // Run a consistency check.
-                self.check();
-
-                return Ok(res);
-            }
-        }
-
-        Err(block)
-    }
-
-    /// Free a block placed in some index bound.
-    ///
-    /// This will at maximum insert one element.
-    ///
-    /// See [`free`](#method.free) for more information.
-    #[inline]
-    fn free_bound(&mut self, ind: Range<usize>, mut block: Block) {
-        // Logging.
-        bk_log!(self;ind, "Freeing {:?}.", block);
-
-        // Short circuit in case of empty block.
-        if block.is_empty() { return; }
-
-        // When compiled with `security`, we zero this block.
-        block.sec_zero();
-
-        if ind.start == self.pool.len() {
-            self.push(block);
-            return;
-        }
-
-        // Assertions...
-        debug_assert!(self.find(&block) == ind.start, "Block is not inserted at the appropriate \
-                      index.");
-
-        // Try to merge it with the block to the right.
-        if ind.end < self.pool.len() && block.left_to(&self.pool[ind.end]) {
-            // Merge the block with the rightmost block in the range.
-            block.merge_right(&mut self.remove_at(ind.end))
-                .expect("Unable to merge block right to the block at the end of the range");
-
-            // The merging succeeded. We proceed to try to close in the possible gap.
-            if ind.start != 0 && self.pool[ind.start - 1].merge_right(&mut block).is_ok() {
-                // Check consistency.
-                self.check();
-
-                return;
-            }
-        // Dammit, let's try to merge left.
-        } else if ind.start != 0 && self.pool[ind.start - 1].merge_right(&mut block).is_ok() {
-            // Check consistency.
-            self.check();
-
-            return;
-        }
-
-        // Well, it failed, so we insert it the old-fashioned way.
-        self.insert(ind.start, block);
-
-        // Check consistency.
-        self.check();
-    }
-
-    /// Allocate external ("fresh") space.
-    ///
-    /// "Fresh" means that the space is allocated through the breaker.
-    ///
-    /// The returned pointer is guaranteed to be aligned to `align`.
-    fn alloc_external(&mut self, size: usize, align: usize) -> Block {
-        // Logging.
-        bk_log!(self, "Fresh allocation of size {} with alignment {}.", size, align);
-
-        // Break it to me!
-        let res = self.alloc_fresh(size, align);
-
-        // Check consistency.
-        self.check();
-
-        res
-    }
-
-    /// Push an element without reserving.
-    // TODO: Make `push` and `free` one.
-    fn push(&mut self, block: Block) {
-        // Logging.
-        bk_log!(self;self.pool.len(), "Pushing {:?}.", block);
-
-        // Mark the block free.
-        let mut block = block.mark_free();
-
-        // Short-circuit in case on empty block.
-        if !block.is_empty() {
-            // Trigger the new memory event handler.
-            self.on_new_memory();
-
-            // Update the pool byte count.
-            self.total_bytes += block.size();
-
-            // Some assertions...
-            debug_assert!(self.pool.is_empty() || &block > self.pool.last().unwrap(), "Pushing will \
-                          make the list unsorted.");
-
-            // We will try to simply merge it with the last block.
-            if let Some(x) = self.pool.last_mut() {
-                if x.merge_right(&mut block).is_ok() {
-                    return;
-                }
-            }
-
-            // Reserve space and free the old buffer.
-            if let Some(x) = unborrow!(self.reserve(self.pool.len() + 1)) {
-                // Note that we do not set the count down because this isn't setting back our
-                // pushed block.
-
-                self.free(x);
-            }
-
-            // Try again to merge with last block on the off chance reserve pushed something we can
-            // merge with. This has actually happened in testing.
-            if let Some(x) = self.pool.last_mut() {
-                if x.merge_right(&mut block).is_ok() {
-                    return;
-                }
-            }
-
-
-            // Merging failed. Note that trailing empty blocks are not allowed, hence the last block is
-            // the only non-empty candidate which may be adjacent to `block`.
-
-            // Check again that pushing is correct.
-            if self.pool.is_empty() || &block > self.pool.last().unwrap() {
-                // We push.
-                let res = self.pool.push(block);
-
-                // Make some assertions.
-                debug_assert!(res.is_ok(), "Push failed (buffer full).");
-            } else {
-                // `free` handles the count, so we set it back.
-                // TODO: Find a better way to do so.
-                self.total_bytes -= block.size();
-
-                // Can't push because reserve changed the end of the pool.
-                self.free(block);
-            }
-        }
-
-        // Check consistency.
-        self.check();
-    }
-
-    /// Reserve some number of elements, and return the old buffer's block.
-    ///
-    /// # Assumptions
-    ///
-    /// This is assumed to not modify the order. If some block `b` is associated with index `i`
-    /// prior to call of this function, it should be too after it.
-    fn reserve(&mut self, min_cap: usize) -> Option<Block> {
-        // Logging.
-        bk_log!(self;min_cap, "Reserving {}.", min_cap);
-
-        if !self.reserving && (self.pool.capacity() < self.pool.len() + EXTRA_ELEMENTS || self.pool.capacity() < min_cap + EXTRA_ELEMENTS) {
-            // Reserve a little extra for performance reasons.
-            // TODO: This should be moved to some new method.
-            let new_cap = min_cap + EXTRA_ELEMENTS + config::extra_fresh(min_cap);
-
-            // Catch 'em all.
-            debug_assert!(new_cap > self.pool.capacity(), "Reserve shrinks?!");
-
-            // Make sure no unbounded reallocation happens.
-            self.reserving = true;
-
-            // Break it to me!
-            let new_buf = self.alloc_external(new_cap * mem::size_of::<Block>(), mem::align_of::<Block>());
-
-            // Go back to the original state.
-            self.reserving = false;
-
-            // Check consistency.
-            self.check();
-
-            Some(self.pool.refill(new_buf))
-        } else {
-            None
-        }
-    }
-
-    /// Insert a block entry at some index.
-    ///
-    /// If the space is non-empty, the elements will be pushed filling out the empty gaps to the
-    /// right.
-    ///
-    /// # Warning
-    ///
-    /// This might in fact break the order.
-    ///
-    /// # Panics
-    ///
-    /// Panics on when `ind` is greater than the block pool's length.
-    ///
-    /// # Example
-    ///
-    /// We want to insert the block denoted by the tildes into our list. Perform a binary search to
-    /// find where insertion is appropriate.
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I------I
-    /// B < here                      I--------I
-    /// l                                              I------------I
-    /// k
-    /// s                                                             I---I
-    ///                  I~~~~~~~~~~I
-    /// ```
-    ///
-    /// We keep pushing the blocks to the right to the next entry until a empty entry is reached:
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I------I
-    /// B < here                      I--------I <~ this one cannot move down, due to being blocked.
-    /// l
-    /// k                                              I------------I <~ thus we have moved this one down.
-    /// s                                                             I---I
-    ///              I~~~~~~~~~~I
-    /// ```
-    ///
-    /// Repeating yields:
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I------I
-    /// B < here
-    /// l                             I--------I <~ this one cannot move down, due to being blocked.
-    /// k                                              I------------I <~ thus we have moved this one down.
-    /// s                                                             I---I
-    ///              I~~~~~~~~~~I
-    /// ```
-    ///
-    /// Now an empty space is left out, meaning that we can insert the block:
-    ///
-    /// ```notrust
-    ///    Address space
-    ///   I------I
-    /// B            I----------I
-    /// l                             I--------I
-    /// k                                              I------------I
-    /// s                                                             I---I
-    /// ```
-    ///
-    /// The insertion is now completed.
-    #[inline]
-    fn insert(&mut self, ind: usize, block: Block) {
-        // Logging.
-        bk_log!(self;ind, "Inserting block {:?}...", block);
-
-        // Bound check.
-        assert!(self.pool.len() >= ind, "Insertion out of bounds.");
-
-        // Some assertions...
-        debug_assert!(self.pool.len() <= ind || block <= self.pool[ind], "Inserting at {} will make \
-                      the list unsorted.", ind);
-        debug_assert!(self.find(&block) == ind, "Block is not inserted at the appropriate index.");
-        debug_assert!(!block.is_empty(), "Inserting an empty block.");
-
-        // Trigger the new memory event handler.
-        self.on_new_memory();
-
-        // Find the next gap, where a used block were.
-        let gap = self.pool
-            .iter()
-            .enumerate()
-            // We only check _after_ the index.
-            .skip(ind)
-            // Until the block is empty.
-            .filter(|&(_, x)| x.is_empty())
-            .next()
-            .map(|(n, _)| n);
-
-        // Log the operation.
-        bk_log!(self;ind, "Moving all blocks right to {} blocks to the right.",
-             gap.unwrap_or_else(|| self.pool.len()));
-
-        // The old vector's buffer.
-        let mut old_buf = None;
-
-        unsafe {
-            // LAST AUDIT: 2016-08-21 (Ticki).
-
-            // Memmove the elements to make a gap to the new block.
-            ptr::copy(self.pool.get_unchecked(ind) as *const Block,
-                      self.pool.get_unchecked_mut(ind + 1) as *mut Block,
-                      // The gap defaults to the end of the pool.
-                      gap.unwrap_or_else(|| {
-                          // We will only extend the length if we were unable to fit it into the current length.
-
-                          // Loooooooging...
-                          bk_log!(self;ind, "Block pool not long enough for shift. Extending.");
-
-                          // Reserve space. This does not break order, due to the assumption that
-                          // `reserve` never breaks order.
-                          old_buf = unborrow!(self.reserve(self.pool.len() + 1));
-
-                          // We will move a block into reserved memory but outside of the vec's bounds. For
-                          // that reason, we push an uninitialized element to extend the length, which will
-                          // be assigned in the memcpy.
-                          let res = self.pool.push(mem::uninitialized());
-
-                          // Just some assertions...
-                          debug_assert!(res.is_ok(), "Push failed (buffer full).");
-
-                          self.pool.len() - 1
-                      }) - ind);
-
-            // Update the pool byte count.
-            self.total_bytes += block.size();
-
-            // Mark it free and set the element.
-            ptr::write(self.pool.get_unchecked_mut(ind), block.mark_free());
-        }
-
-        // Free the old buffer, if it exists.
-        if let Some(block) = old_buf {
-            self.free(block);
-        }
-
-        // Check consistency.
-        self.check();
-    }
-
-    /// Remove a block.
-    fn remove_at(&mut self, ind: usize) -> Block {
-        // Logging.
-        bk_log!(self;ind, "Removing block at {}.", ind);
-
-        let res = if ind + 1 == self.pool.len() {
-            let block = self.pool[ind].pop();
-            // Make sure there are no trailing empty blocks.
-            let new_len = self.pool.len() - self.pool.iter().rev().take_while(|x| x.is_empty()).count();
-
-            // Truncate the vector.
-            self.pool.truncate(new_len);
-
-            block
-        } else {
-            // Calculate the upper and lower bound
-            let empty = self.pool[ind + 1].empty_left();
-            let empty2 = empty.empty_left();
-
-            // Replace the block at `ind` with the left empty block from `ind + 1`.
-            let block = mem::replace(&mut self.pool[ind], empty);
-
-            // Iterate over the pool from `ind` and down and set it to the  empty of our block.
-            let skip = self.pool.len() - ind;
-            for place in self.pool.iter_mut().rev().skip(skip).take_while(|x| x.is_empty()) {
-                // Empty the blocks.
-                *place = empty2.empty_left();
-            }
-
-            block
-        };
-
-        // Update the pool byte count.
-        self.total_bytes -= res.size();
-
-        // Check consistency.
-        self.check();
-
-        // Mark the block uninitialized to the debugger.
-        res.mark_uninitialized()
-    }
-}

+ 15 - 5
src/brk.rs

@@ -9,7 +9,7 @@ use core::convert::TryInto;
 
 use shim::{syscalls, config};
 
-use {sync, fail};
+use {sync, fail, block, ptr};
 
 /// The BRK mutex.
 ///
@@ -46,7 +46,7 @@ impl BrkLock {
         let expected_brk = self.current_brk().offset(size);
 
         // Break it to me, babe!
-        let old_brk = Pointer::new(syscalls::brk(*expected_brk as *const u8) as *mut u8);
+        let old_brk = Pointer::new(syscalls::brk(expected_brk) as *mut u8);
 
         /// AAAARGH WAY TOO MUCH LOGGING
         ///
@@ -75,7 +75,6 @@ impl BrkLock {
     pub fn release(&mut self, block: Block) -> Result<(), Block> {
         // Check if we are actually next to the program break.
         if self.current_brk() == Pointer::from(block.empty_right()) {
-            // Logging...
             log!(DEBUG, "Releasing {:?} to the OS.", block);
 
             // We are. Now, sbrk the memory back. Do to the condition above, this is safe.
@@ -92,7 +91,6 @@ impl BrkLock {
 
             Ok(())
         } else {
-            // Logging...
             log!(DEBUG, "Unable to release {:?} to the OS.", block);
 
             // Return the block back.
@@ -132,7 +130,7 @@ impl BrkLock {
     ///
     /// This method calls the OOM handler if it is unable to acquire the needed space.
     // TODO: This method is possibly unsafe.
-    pub fn canonical_brk(&mut self, size: usize, align: usize) -> (Block, Block, Block) {
+    pub fn canonical_brk(&mut self, size: block::Size, align: ptr::Align) -> (Block, Block, Block) {
         // Calculate the canonical size (extra space is allocated to limit the number of system calls).
         let brk_size = size + config::extra_brk(size) + align;
 
@@ -213,4 +211,16 @@ mod test {
             assert!(*brk1 < *brk2);
         }
     }
+
+    #[test]
+    fn test_brk_right_segment_change() {
+        unsafe {
+            let brk1 = lock().sbrk(5).unwrap();
+            let brk2 = lock().sbrk(100).unwrap();
+
+            assert_eq!(brk1.offset(5), brk2);
+            assert_eq!(brk2.offset(100), current_brk());
+            assert_eq!(lock().sbrk(0), current_brk());
+        }
+    }
 }

+ 27 - 2
src/cell.rs

@@ -3,6 +3,8 @@
 use core::cell::UnsafeCell;
 use core::mem;
 
+use take::take;
+
 /// A move cell.
 ///
 /// This allows you to take ownership and replace the internal data with a new value. The
@@ -28,11 +30,25 @@ impl<T> MoveCell<T> {
         mem::replace(unsafe {
             // LAST AUDIT: 2016-08-21 (Ticki).
 
-            // This is safe due to never aliasing the value, but simply transfering ownership to
+            // This is safe due to never aliasing the value, but simply transferring ownership to
             // the caller.
             &mut *self.inner.get()
         }, new)
     }
+
+    /// Get a reference to the inner value.
+    ///
+    /// Safety is enforced statically due to the guarantee of mutual exclusion in mutable
+    /// references.
+    pub fn get(&mut self) -> &mut T {
+        mem::replace(unsafe {
+            // LAST AUDIT: 2016-09-01 (Ticki).
+
+            // This is safe due to the `&mut self`, enforcing the guarantee of uniqueness. This
+            // will thus not alias it for the lifetime of that reference.
+            &mut *self.inner.get()
+        }
+    }
 }
 
 #[cfg(test)]
@@ -40,9 +56,18 @@ mod test {
     use super::*;
 
     #[test]
-    fn test_cell() {
+    fn test_replace() {
         let cell = MoveCell::new(200);
         assert_eq!(cell.replace(300), 200);
         assert_eq!(cell.replace(4), 300);
     }
+
+    #[test]
+    fn test_get() {
+        let mut cell = MoveCell::new(200);
+        assert_eq!(*cell.get(), 200);
+
+        *cell.get() = 300;
+        assert_eq!(*cell.get(), 300);
+    }
 }

+ 99 - 0
src/derive.rs

@@ -0,0 +1,99 @@
+//! Helper macros for deriving items.
+
+/// Derive an integer newtype (`Ord`, `PartialOrd`, `Eq`, `Add` etc.) of `usize`.
+macro_rules! usize_newtype {
+    ($name:ident) => {
+        #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
+        struct $ident(usize);
+
+        __usize_newtype!($ident)
+    };
+    (pub $name:ident) => {
+        #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
+        pub struct $ident(usize);
+
+        __usize_newtype!($ident)
+    };
+}
+
+/// An internal method to derive integer traits for a newtype.
+#[doc(hidden)]
+macro_rules! __usize_newtype {
+    ($ty:ty) => {
+        impl ::std::ops::Add for $ty {
+            fn add(self, rhs: $ty) -> $ty {
+                $ty(self.0 + rhs)
+            }
+        }
+
+        impl ::std::ops::Sub for $ty {
+            fn sub(self, rhs: $ty) -> $ty {
+                $ty(self.0 - rhs)
+            }
+        }
+
+        impl ::std::ops::Sub for $ty {
+            fn mul(self, rhs: $ty) -> $ty {
+                $ty(self.0 * rhs)
+            }
+        }
+
+        impl ::std::ops::Neg for $ty {
+            fn neg(selfy) -> $ty {
+                $ty(-self.0)
+            }
+        }
+
+        impl ::std::iter::Step for $ty {
+            fn step(&self, by: &$ty) -> Option<$ty> {
+                unimplemented!();
+            }
+
+            fn steps_between(start: &$ty, end: &$ty, by: &$ty) -> Option<usize> {
+                unimplemented!();
+            }
+
+            fn steps_between_by_one(start: &$ty, end: &$ty) -> Option<usize> {
+                unimplemented!();
+            }
+
+            fn is_negative(&self) -> bool {
+                false
+            }
+
+            fn replace_one(&mut self) -> $ty {
+                unimplemented!();
+            }
+
+            fn replace_zero(&mut self) -> $ty {
+                unimplemented!();;
+            }
+
+            fn add_one(&self) -> $ty {
+                $ty(self.0 + 1)
+            }
+            fn sub_one(&self) -> $ty {
+                $ty(self.0 - 1)
+            }
+        }
+    };
+}
+
+/// Derives `Deref` and `DerefMut` to the `inner` field.
+macro_rules! derive_deref {
+    ($imp:ty, $target:ty) => {
+        impl ::core::ops::Deref for $imp {
+            type Target = $target;
+
+            fn deref(&self) -> &$target {
+                &self.inner
+            }
+        }
+
+        impl ::core::ops::DerefMut for $imp {
+            fn deref_mut(&mut self) -> &mut $target {
+                &mut self.inner
+            }
+        }
+    };
+}

+ 0 - 2
src/fail.rs

@@ -56,7 +56,6 @@ pub fn oom() -> ! {
 /// This is called when the process is out-of-memory.
 #[inline]
 pub fn set_oom_handler(handler: fn() -> !) {
-    // Logging...
     log!(NOTE, "Setting the global OOM handler.");
 
     OOM_HANDLER.store(handler as *mut (), atomic::Ordering::SeqCst);
@@ -70,7 +69,6 @@ pub fn set_oom_handler(handler: fn() -> !) {
 #[inline]
 #[cfg(feature = "tls")]
 pub fn set_thread_oom_handler(handler: fn() -> !) {
-    // Logging...
     log!(NOTE, "Setting the thread OOM handler.");
 
     THREAD_OOM_HANDLER.with(|thread_oom| {

+ 12 - 0
src/lazy_init.rs

@@ -39,7 +39,9 @@ impl<F: FnMut() -> T, T> LazyInit<F, T> {
         let inner;
 
         match self.state {
+            // The lazy initializer has run, and the inner value is initialized.
             State::Initialized(ref mut x) => return x,
+            // It is uninitialized, run the initializer.
             State::Uninitialized(ref mut f) => inner = f(),
         }
 
@@ -66,6 +68,8 @@ impl<F: FnMut() -> T, T> LazyInit<F, T> {
     }
 }
 
+
+
 #[cfg(test)]
 mod test {
     use super::*;
@@ -81,6 +85,14 @@ mod test {
         assert_eq!(*lazy.get(), 400);
     }
 
+    #[test]
+    fn test_into_inner() {
+        let mut lazy = LazyInit::new(|| 300);
+
+        *lazy.get() = 442;
+        assert_eq!(lazy.into_inner(), 442);
+    }
+
     #[test]
     fn test_laziness() {
         let is_called = Cell::new(false);

+ 2 - 1
src/leak.rs

@@ -13,4 +13,5 @@ use prelude::*;
 pub unsafe trait Leak {}
 
 unsafe impl Leak for Block {}
-unsafe impl<T: Copy> Leak for T {}
+unsafe impl<T> Leak for Jar<T> {}
+unsafe impl<T> Leak for T where T: Copy {}

+ 11 - 5
src/lib.rs

@@ -18,16 +18,19 @@
 #![feature(allocator, const_fn, core_intrinsics, stmt_expr_attributes, drop_types_in_const,
            nonzero, optin_builtin_traits, type_ascription, question_mark, thread_local, linkage,
            try_from)]
-#![warn(missing_docs, cast_precision_loss, cast_sign_loss, cast_possible_wrap,
-        cast_possible_truncation, filter_map, if_not_else, items_after_statements,
-        invalid_upcast_comparisons, mutex_integer, nonminimal_bool, shadow_same, shadow_unrelated,
-        single_match_else, string_add, string_add_assign, wrong_pub_self_convention)]
+#![warn(missing_docs, missing_docs_in_private_items, cast_precision_loss, cast_sign_loss,
+        cast_possible_wrap, cast_possible_truncation, filter_map, if_not_else,
+        items_after_statements, invalid_upcast_comparisons, mutex_integer, nonminimal_bool,
+        shadow_same, shadow_unrelated, single_match_else, string_add, string_add_assign,
+        wrong_pub_self_convention)]
 
 #[macro_use]
 #[no_link]
 extern crate unborrow;
 extern crate ralloc_shim as shim;
 
+#[macro_use]
+mod derive;
 #[macro_use]
 mod log;
 #[macro_use]
@@ -37,8 +40,9 @@ mod tls;
 mod symbols;
 
 mod allocator;
+mod arena;
+mod bk;
 mod block;
-mod bookkeeper;
 mod brk;
 mod cell;
 mod fail;
@@ -46,7 +50,9 @@ mod lazy_init;
 mod leak;
 mod prelude;
 mod ptr;
+mod random;
 mod sync;
+mod take;
 mod vec;
 
 pub use allocator::{alloc, free, realloc, realloc_inplace};

+ 30 - 259
src/log.rs

@@ -6,71 +6,56 @@
 ///
 /// The first argument defines the log level, the rest of the arguments are just `write!`-like
 /// formatters.
+///
+/// # Log levels
+///
+/// 1. `INTERNAL`: For things that are used in debugging of `ralloc`, but rarely of relevance or
+///    usage when debugging.
+/// 2. `DEBUG`: For messages which helps debugging `ralloc` (not the program, but `ralloc`).
+/// 3. `CALL`: For calls into `ralloc`. This is only inteded for use when entering `ralloc`.
+/// 4. `NOTE`: Information which is not necessarily a red flag, but interesting for the user.
+/// 5. `WARNING`: For indicating that something might have went wrong.
+/// 6. `ERROR`: For error messages, both fatal and non-fatal ones.
 #[macro_export]
 macro_rules! log {
     (INTERNAL, $( $x:tt )*) => {
-        log!(@["INTERNAL: ", 1], $( $x )*);
+        log!(@["INTERNAL", 1], $( $x )*);
     };
     (DEBUG, $( $x:tt )*) => {
-        log!(@["DEBUG:    ", 2], $( $x )*);
+        log!(@["DEBUG", 2], $( $x )*);
     };
     (CALL, $( $x:tt )*) => {
-        log!(@["CALL:     ", 3], $( $x )*);
+        log!(@["CALL", 3], $( $x )*);
     };
     (NOTE, $( $x:tt )*) => {
-        log!(@["NOTE:     ", 5], $( $x )*);
+        log!(@["NOTE", 5], $( $x )*);
     };
     (WARNING, $( $x:tt )*) => {
-        log!(@["WARNING:  ", 5], $( $x )*);
+        log!(@["WARNING", 5], $( $x )*);
     };
     (ERROR, $( $x:tt )*) => {
-        log!(@["ERROR:    ", 6], $( $x )*);
+        log!(@["ERROR", 6], $( $x )*);
     };
     (@[$kind:expr, $lv:expr], $( $arg:expr ),*) => {
+        // Sneks gunna snek
+        //
+        //     ()
+        //   ()  ()
+        //  ()  ()     ()
+        //   ()  ()  ()
+        //  ()     ()
+        //  \/
+        // [**]
+        //  |
+        //  ^
+
         #[cfg(feature = "log")]
         {
             use core::fmt::Write;
 
-            use log::internal::{LogWriter, level};
-
-            // Set the level.
-            if level($lv) {
-                // Print the pool state.
-                let mut log = LogWriter::new();
-                // Print the log message.
-                let _ = write!(log, $kind);
-                let _ = write!(log, $( $arg ),*);
-                let _ = writeln!(log, " (at {}:{})", file!(), line!());
-            }
-        }
-    };
-}
-
-/// Log with bookkeeper data to the appropriate source.
-///
-/// The first argument this takes is of the form `pool;cursor`, which is used to print the
-/// block pools state. `cursor` is what the operation "revolves around" to give a sense of
-/// position.
-///
-/// If the `;cursor` part is left out, no cursor will be printed.
-///
-/// The rest of the arguments are just normal formatters.
-///
-/// This logs to level 2.
-#[macro_export]
-macro_rules! bk_log {
-    ($pool:expr, $( $arg:expr ),*) => {
-        bk_log!($pool;(), $( $arg ),*);
-    };
-    ($bk:expr;$cur:expr, $( $arg:expr ),*) => {
-        #[cfg(feature = "log")]
-        {
-            use log::internal::{IntoCursor, BlockLogger};
+            use log::__internal::{LogWriter, level};
 
-            log!(INTERNAL, "({:2}) {:10?} : {}", $bk.id, BlockLogger {
-                cur: $cur.clone().into_cursor(),
-                blocks: &$bk.pool,
-            }, format_args!($( $arg ),*));
+            shim::log::write($lv, $kind, format_args!($( $arg ),*), file!(), line!());
         }
     };
 }
@@ -133,217 +118,3 @@ macro_rules! assert_eq {
         assert!(left == right, "(left: '{:?}', right: '{:?}')", left, right)
     })
 }
-
-/// Top-secret module.
-#[cfg(feature = "log")]
-pub mod internal {
-    use prelude::*;
-
-    use core::fmt;
-    use core::cell::Cell;
-    use core::ops::Range;
-
-    use shim::config;
-
-    use sync;
-
-    /// The log lock.
-    ///
-    /// This lock is used to avoid bungling and intertwining the log.
-    #[cfg(not(feature = "no_log_lock"))]
-    pub static LOG_LOCK: Mutex<()> = Mutex::new(());
-
-    /// A log writer.
-    ///
-    /// This writes to the shim logger.
-    pub struct LogWriter {
-        /// The inner lock.
-        #[cfg(not(feature = "no_log_lock"))]
-        _lock: sync::MutexGuard<'static, ()>,
-    }
-
-    impl LogWriter {
-        /// Standard error output.
-        pub fn new() -> LogWriter {
-            #[cfg(feature = "no_log_lock")]
-            {
-                LogWriter {}
-            }
-
-            #[cfg(not(feature = "no_log_lock"))]
-            LogWriter {
-                _lock: LOG_LOCK.lock(),
-            }
-        }
-    }
-
-    impl fmt::Write for LogWriter {
-        fn write_str(&mut self, s: &str) -> fmt::Result {
-            if config::log(s) == !0 { Err(fmt::Error) } else { Ok(()) }
-        }
-    }
-
-    /// A "cursor".
-    ///
-    /// Cursors represents a block or an interval in the log output. This trait is implemented for
-    /// various types that can represent a cursor.
-    pub trait Cursor {
-        /// Iteration at n.
-        ///
-        /// This is called in the logging loop. The cursor should then write, what it needs, to the
-        /// formatter if the underlying condition is true.
-        ///
-        /// For example, a plain position cursor will write `"|"` when `n == self.pos`.
-        // TODO: Use an iterator instead.
-        fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result;
-
-        /// The after hook.
-        ///
-        /// This is runned when the loop is over. The aim is to e.g. catch up if the cursor wasn't
-        /// printed (i.e. is out of range).
-        fn after(&self, f: &mut fmt::Formatter) -> fmt::Result;
-    }
-
-    /// Types that can be converted into a cursor.
-    pub trait IntoCursor {
-        /// The end result.
-        type Cursor: Cursor;
-
-        /// Convert this value into its equivalent cursor.
-        fn into_cursor(self) -> Self::Cursor;
-    }
-
-    /// A single-point cursor.
-    pub struct UniCursor {
-        /// The position where this cursor will be placed.
-        pos: usize,
-        /// Is this cursor printed?
-        ///
-        /// This is used for the after hook.
-        is_printed: Cell<bool>,
-    }
-
-    impl Cursor for UniCursor {
-        fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result {
-            if self.pos == n {
-                self.is_printed.set(true);
-                write!(f, "|")?;
-            }
-
-            Ok(())
-        }
-
-        fn after(&self, f: &mut fmt::Formatter) -> fmt::Result {
-            if !self.is_printed.get() {
-                write!(f, "…|")?;
-            }
-
-            Ok(())
-        }
-    }
-
-    impl IntoCursor for usize {
-        type Cursor = UniCursor;
-
-        fn into_cursor(self) -> UniCursor {
-            UniCursor {
-                pos: self,
-                is_printed: Cell::new(false),
-            }
-        }
-    }
-
-    impl Cursor for () {
-        fn at(&self, _: &mut fmt::Formatter, _: usize) -> fmt::Result { Ok(()) }
-
-        fn after(&self, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) }
-    }
-
-    impl IntoCursor for () {
-        type Cursor = ();
-
-        fn into_cursor(self) -> () {
-            ()
-        }
-    }
-
-    /// A interval/range cursor.
-    ///
-    /// The start of the range is marked by `[` and the end by `]`.
-    pub struct RangeCursor {
-        /// The range of this cursor.
-        range: Range<usize>,
-    }
-
-    impl Cursor for RangeCursor {
-        fn at(&self, f: &mut fmt::Formatter, n: usize) -> fmt::Result {
-            if self.range.start == n {
-                write!(f, "[")?;
-            } else if self.range.end == n {
-                write!(f, "]")?;
-            }
-
-            Ok(())
-        }
-
-        fn after(&self, _: &mut fmt::Formatter) -> fmt::Result { Ok(()) }
-    }
-
-    impl IntoCursor for Range<usize> {
-        type Cursor = RangeCursor;
-
-        fn into_cursor(self) -> RangeCursor {
-            RangeCursor {
-                range: self,
-            }
-        }
-    }
-
-    /// A "block logger".
-    ///
-    /// This intend to show the structure of a block pool. The syntax used is like:
-    ///
-    /// ```
-    /// xxx__|xx_
-    /// ```
-    ///
-    /// where `x` denotes an non-empty block. `_` denotes an empty block, with `|` representing the
-    /// cursor.
-    pub struct BlockLogger<'a, T> {
-        /// The cursor.
-        ///
-        /// This is where the `|` will be printed.
-        pub cur: T,
-        /// The blocks.
-        pub blocks: &'a [Block],
-    }
-
-    impl<'a, T: Cursor> fmt::Debug for BlockLogger<'a, T> {
-        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-            // TODO: Handle alignment etc.
-
-            for (n, i) in self.blocks.iter().enumerate() {
-                self.cur.at(f, n)?;
-
-                if i.is_empty() {
-                    // Empty block.
-                    write!(f, "_")?;
-                } else {
-                    // Non-empty block.
-                    write!(f, "x")?;
-                }
-            }
-
-            self.cur.after(f)?;
-
-            Ok(())
-        }
-    }
-
-    /// Check if this log level is enabled.
-    #[allow(absurd_extreme_comparisons)]
-    #[inline]
-    pub fn level(lv: u8) -> bool {
-        lv >= config::MIN_LOG_LEVEL
-    }
-}

+ 2 - 1
src/prelude.rs

@@ -5,6 +5,7 @@
 pub use block::Block;
 pub use cell::MoveCell;
 pub use lazy_init::LazyInit;
+pub use leak::Leak;
+pub use ptr::{Pointer, Jar};
 pub use sync::Mutex;
-pub use ptr::Pointer;
 pub use vec::Vec;

+ 88 - 3
src/ptr.rs

@@ -1,7 +1,9 @@
 //! Pointer wrappers.
 
+use prelude::*;
+
 use core::nonzero::NonZero;
-use core::{ops, marker};
+use core::{ops, marker, mem};
 
 /// A pointer wrapper type.
 ///
@@ -54,6 +56,11 @@ impl<T> Pointer<T> {
     /// Cast this pointer into a pointer to another type.
     ///
     /// This will simply transmute the pointer, leaving the actual data unmodified.
+    ///
+    /// # Why not `From`?
+    ///
+    /// `T` implements `From<T>`, making it (currently) impossible to implement this type of cast
+    /// with `From`. [RFC #1658](https://github.com/rust-lang/rfcs/pull/1658) fixes this.
     #[inline]
     pub fn cast<U>(self) -> Pointer<U> {
         Pointer {
@@ -78,6 +85,12 @@ impl<T> Pointer<T> {
     pub unsafe fn offset(self, diff: isize) -> Pointer<T> {
         Pointer::new(self.ptr.offset(diff))
     }
+
+    /// Is this pointer aligned to `align`?
+    #[inline]
+    pub fn aligned_to(&self, align: usize) -> bool {
+        *self.ptr as usize % align == 0
+    }
 }
 
 impl<T> Default for Pointer<T> {
@@ -98,6 +111,78 @@ impl<T> ops::Deref for Pointer<T> {
     }
 }
 
+/// A safe, owning pointer (container).
+///
+/// The name is derives libstd's `Box`, which is centered around heap management, and will free the
+/// inner memory on drop. This limitation somewhat limits the scope, so we use a primitive where
+/// freeing and allocating the inner memory is managed by the user.
+#[must_use = "`Jar` does not handle the destructor automatically, please free it into an arena to \
+              avoid memory leaks."]
+pub struct Jar<T: Leak> {
+    /// The inner pointer.
+    ///
+    /// This has four guarantees:
+    ///
+    /// 1. It is valid and initialized.
+    /// 2. The lifetime is tied to the ownership of the box (i.e. it is valid until manually
+    ///    deallocated).
+    /// 3. It is aligned to the alignment of `T`.
+    /// 4. It is non-aliased.
+    ptr: Pointer<T>,
+}
+
+impl<T: Leak> Jar<T> {
+    /// Create a jar from a raw pointer.
+    ///
+    /// # Safety
+    ///
+    /// Make sure the pointer is valid, initialized, non-aliased, and aligned. If any of these
+    /// invariants are broken, unsafety occurs.
+    #[inline]
+    pub unsafe fn from_raw(ptr: Pointer<T>) -> Jar<T> {
+        debug_assert!(ptr.aligned_to(mem::align_of::<T>()), "`ptr` is unaligned to `T`.");
+
+        Jar { ptr: ptr }
+    }
+}
+
+impl<T: Leak> ops::Deref for Jar<T> {
+    type Target = T;
+
+    #[inline]
+    fn deref(&self) -> &T {
+        unsafe {
+            // LAST AUDIT: 2016-08-24 (Ticki).
+
+            &*self.ptr
+        }
+    }
+}
+
+impl<T: Leak> ops::DerefMut for Jar<T> {
+    #[inline]
+    fn deref_mut(&self) -> &mut T {
+        unsafe {
+            // LAST AUDIT: 2016-08-24 (Ticki).
+
+            &mut *self.ptr
+        }
+    }
+}
+
+impl<T: Leak> From<Jar<T>> for Pointer<T> {
+    fn from(jar: Jar<T>) -> Pointer<T> {
+        jar.ptr
+    }
+}
+
+#[cfg(debug_assertions)]
+impl<T: Leak> Drop for Jar<T> {
+    fn drop(&mut self) {
+        panic!("Leaking a `Jar`.");
+    }
+}
+
 #[cfg(test)]
 mod test {
     use super::*;
@@ -107,7 +192,7 @@ mod test {
         let mut x = [b'a', b'b'];
 
         unsafe {
-            let ptr = Pointer::new(&mut x[0] as *mut u8);
+            let ptr = Pointer::new(&mut x[0]);
             assert_eq!(**ptr, b'a');
             assert_eq!(**ptr.clone().cast::<[u8; 1]>(), [b'a']);
             assert_eq!(**ptr.offset(1), b'b');
@@ -116,7 +201,7 @@ mod test {
         let mut y = ['a', 'b'];
 
         unsafe {
-            let ptr = Pointer::new(&mut y[0] as *mut char);
+            let ptr = Pointer::new(&mut y[0]);
             assert_eq!(**ptr.clone().cast::<[char; 1]>(), ['a']);
             assert_eq!(**ptr.offset(1), 'b');
         }

+ 62 - 0
src/random.rs

@@ -0,0 +1,62 @@
+//! Pseudorandom number generators.
+//!
+//! `ralloc` makes use of probabilistic data structures which often requires randomness. This
+//! module provides functions giving pseudorandom output based on `xorshift+`.
+
+use core::cell::Cell;
+
+tls! {
+    /// The randomness state.
+    ///
+    /// This is updated when a new random integer is read.
+    // TODO: Upon new threads, this should fetch from a global variable to ensure unique stream.
+    // Currently, this doesn't matter, but it might for data structures used in the future.
+    static STATE: Cell<[u64; 2]> = Cell::new([0xBADF00D1, 0xDEADBEEF]);
+}
+
+/// Get a pseudorandom integer.
+///
+/// Note that this is full-cycle, so apply a modulo when true equidistribution is needed.
+#[inline]
+pub fn get() -> u64 {
+    STATE.with(|state| {
+        // Fetch the state.
+        let mut state = state.get();
+
+        // Store the first and second part.
+        let mut x = state[0];
+        let y = state[1];
+
+        // Put the second part into the first slot.
+        state[0] = y;
+        // Twist the first slot.
+        x ^= x << 23;
+        // Update the second slot.
+        state[1] = x ^ y ^ (x >> 17) ^ (y >> 26);
+
+        // Put back the state.
+        STATE.set(state);
+
+        // Generate the final integer.
+        state[1].wrapping_add(y);
+    })
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_distinct() {
+        assert!(get() != get());
+        assert!(get() != get());
+        assert!(get() != get());
+        assert!(get() != get());
+        assert!(get() != get());
+        assert!(get() != get());
+        assert!(get() != get());
+        assert!(get() != get());
+        assert!(get() != get());
+        assert!(get() != get());
+    }
+}

+ 3 - 3
src/sync.rs

@@ -54,7 +54,7 @@ impl<T> Mutex<T> {
 /// A mutex guard.
 ///
 /// This acts as the lock.
-#[must_use]
+#[must_use = "Locking a mutex without using the mutex guard is a waste of cycles."]
 pub struct MutexGuard<'a, T: 'a> {
     /// The parent mutex.
     mutex: &'a Mutex<T>,
@@ -93,8 +93,8 @@ impl<'a, T> ops::DerefMut for MutexGuard<'a, T> {
     }
 }
 
-unsafe impl<T: Send> Send for Mutex<T> {}
-unsafe impl<T: Send> Sync for Mutex<T> {}
+unsafe impl<T> Send for Mutex<T> where T: Send {}
+unsafe impl<T> Sync for Mutex<T> where T: Send {}
 
 #[cfg(test)]
 mod test {

+ 71 - 0
src/take.rs

@@ -0,0 +1,71 @@
+//! Functions for temporarily moving out of ownership.
+
+// TODO: https://github.com/rust-lang/rfcs/pull/1736
+
+use core::{mem, intrinsics};
+
+/// A guarding type which will exit upon drop.
+///
+/// This is used for catching unwinding and transforming it into abort.
+struct ExitGuard;
+
+impl Drop for ExitGuard {
+    fn drop(&mut self) {
+        // To make sure the user gets a meaningful error message (as opposed to a simple abort), we
+        // log to the `ERROR` level.
+        log!(ERROR, "Unwinding in a `take` closure.");
+
+        // Just abort the program.
+        unsafe { intrinsics::abort(); }
+    }
+}
+
+/// Temporarily take ownership of the inner value of a reference.
+///
+/// This essentially works as a generalized version of `mem::replace`, which instead takes a
+/// closure that will return the replacement value.
+///
+/// This will abort on panics.
+#[inline]
+pub fn replace_with<T, F>(val: &mut T, replace: F)
+    where F: FnOnce(T) -> T {
+    // Guard against unwinding.
+    let guard = ExitGuard;
+
+    unsafe {
+        // Take out the value behind the pointer.
+        let old = ptr::read(val);
+        // Run the closure.
+        let new = closure(old);
+        // Put the result back.
+        ptr::write(val, new);
+    }
+
+    // Drop the guard.
+    mem::forget(guard);
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    use core::cell::Cell;
+
+    #[test]
+    fn test_replace_with() {
+        let mut x = Some("test");
+        replace_with(&mut x, |_| None);
+        assert!(x.is_none());
+    }
+
+    #[test]
+    fn test_replace_with_2() {
+        let is_called = Cell::new(false);
+        let mut x = 2;
+        replace_with(&mut x, |_| {
+            is_called.set(true);
+            3
+        });
+        assert!(is_called.get());
+    }
+}

+ 32 - 5
src/tls.rs

@@ -2,6 +2,8 @@
 //!
 //! This module provides lightweight abstractions for TLS similar to the ones provided by libstd.
 
+use prelude::*;
+
 use core::{marker, mem};
 
 use shim::thread_destructor;
@@ -18,7 +20,7 @@ impl<T: 'static> Key<T> {
     /// # Safety
     ///
     /// This is invariant-breaking (assumes thread-safety) and thus unsafe.
-    pub const unsafe fn new(inner: T) -> Key<T> {
+    pub const unsafe fn new(inner: T) -> Key<T> where T: Leak {
         Key { inner: inner }
     }
 
@@ -31,7 +33,6 @@ impl<T: 'static> Key<T> {
     #[inline]
     pub fn with<F, R>(&'static self, f: F) -> R
         where F: FnOnce(&T) -> R {
-        // Logging.
         log!(INTERNAL, "Accessing TLS variable.");
 
         f(&self.inner)
@@ -43,10 +44,9 @@ impl<T: 'static> Key<T> {
     // TODO: Make this automatic on `Drop`.
     #[inline]
     pub fn register_thread_destructor(&'static self, dtor: extern fn(&T)) {
-        // Logging.
         log!(INTERNAL, "Registering thread destructor.");
 
-        thread_destructor::register(&self.inner as *const T as *const u8 as *mut u8, unsafe {
+        thread_destructor::register(&self.inner as *mut u8, unsafe {
             // LAST AUDIT: 2016-08-21 (Ticki).
 
             // This is safe due to sharing memory layout.
@@ -66,7 +66,9 @@ unsafe impl<T> marker::Sync for Key<T> {}
 /// For this reason, in contrast to other `static`s in Rust, this need not thread-safety, which is
 /// what this macro "fixes".
 macro_rules! tls {
-    (static $name:ident: $ty:ty = $val:expr;) => { tls! { #[] static $name: $ty = $val; } };
+    (static $name:ident: $ty:ty = $val:expr;) => {
+        tls! { #[] static $name: $ty = $val; }
+    };
     (#[$($attr:meta),*] static $name:ident: $ty:ty = $val:expr;) => {
         $(#[$attr])*
         #[thread_local]
@@ -79,3 +81,28 @@ macro_rules! tls {
         };
     }
 }
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    use cell::MoveCell;
+
+    #[test]
+    fn test_tls() {
+        tls!(static HELLO: &'static str = "hello");
+
+        HELLO.with(|x| assert_eq!(x, "hello"));
+    }
+
+    #[test]
+    fn test_mutability() {
+        tls!(static HELLO: MoveCell<u32> = MoveCell::new(3));
+
+        HELLO.with(|x| assert_eq!(x.replace(4), 3));
+        HELLO.with(|x| assert_eq!(x.replace(5), 4));
+        HELLO.with(|x| assert_eq!(x.replace(10), 5));
+        HELLO.with(|x| assert_eq!(x.replace(0), 10));
+        HELLO.with(|x| assert_eq!(x.replace(0), 0));
+    }
+}

+ 11 - 10
src/vec.rs

@@ -4,7 +4,8 @@ use prelude::*;
 
 use core::{slice, ops, mem, ptr};
 
-use leak::Leak;
+// Derive the length newtype.
+usize_newtype!(pub VecElem);
 
 /// A low-level vector primitive.
 ///
@@ -16,11 +17,11 @@ pub struct Vec<T: Leak> {
     /// The capacity of the buffer.
     ///
     /// This demonstrates the lengths before reallocation is necessary.
-    cap: usize,
+    cap: VecElem,
     /// The length of the vector.
     ///
     /// This is the number of elements from the start, that is initialized, and can be read safely.
-    len: usize,
+    len: VecElem,
 }
 
 impl<T: Leak> Vec<T> {
@@ -31,7 +32,7 @@ impl<T: Leak> Vec<T> {
     /// This is unsafe, since it won't initialize the buffer in any way, possibly breaking type
     /// safety, memory safety, and so on. Thus, care must be taken upon usage.
     #[inline]
-    pub unsafe fn from_raw_parts(block: Block, len: usize) -> Vec<T> {
+    pub unsafe fn from_raw_parts(block: Block, len: VecElem) -> Vec<T> {
         Vec {
             len: len,
             cap: block.size() / mem::size_of::<T>(),
@@ -76,7 +77,7 @@ impl<T: Leak> Vec<T> {
 
     /// Get the capacity of this vector.
     #[inline]
-    pub fn capacity(&self) -> usize {
+    pub fn capacity(&self) -> VecElem {
         self.cap
     }
 
@@ -132,7 +133,7 @@ impl<T: Leak> Vec<T> {
     /// # Panics
     ///
     /// Panics on out-of-bound.
-    pub fn truncate(&mut self, len: usize) {
+    pub fn truncate(&mut self, len: VecElem) {
         // Bound check.
         assert!(len <= self.len, "Out of bound.");
 
@@ -193,7 +194,7 @@ impl<T: Leak> ops::Deref for Vec<T> {
             // LAST AUDIT: 2016-08-21 (Ticki).
 
             // The invariants maintains safety.
-            slice::from_raw_parts(*self.ptr as *const T, self.len)
+            slice::from_raw_parts(self.ptr, self.len)
         }
     }
 }
@@ -205,7 +206,7 @@ impl<T: Leak> ops::DerefMut for Vec<T> {
             // LAST AUDIT: 2016-08-21 (Ticki).
 
             // The invariants maintains safety.
-            slice::from_raw_parts_mut(*self.ptr as *mut T, self.len)
+            slice::from_raw_parts_mut(self.ptr, self.len)
         }
     }
 }
@@ -219,7 +220,7 @@ mod test {
         let mut buffer = [b'a'; 32];
         let mut vec = unsafe {
             Vec::from_raw_parts(
-                Block::from_raw_parts(Pointer::new(&mut buffer[0] as *mut u8), 32),
+                Block::from_raw_parts(Pointer::new(&mut buffer[0]), 32),
                 16
             )
         };
@@ -234,7 +235,7 @@ mod test {
 
         unsafe {
             assert_eq!(vec.refill(
-                Block::from_raw_parts(Pointer::new(&mut buffer[0] as *mut u8), 32)).size(),
+                Block::from_raw_parts(Pointer::new(&mut buffer[0]), 32)).size(),
                 32
             );
         }