diff --git a/Cargo.lock b/Cargo.lock
index 3a87016cb16700cdbd62825d172dc97ffb4f8cb4..d16a780e1a286e67fa5744bba4982d4a020f9fef 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -32,6 +32,41 @@ dependencies = [
  "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "auto_enums"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "auto_enums_core 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "auto_enums_derive 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "auto_enums_core"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "auto_enums_derive"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "derive_utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "autocfg"
 version = "0.1.2"
@@ -224,6 +259,16 @@ dependencies = [
  "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "derive_utils"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "either"
 version = "1.5.2"
@@ -306,6 +351,7 @@ name = "ion-shell"
 version = "1.0.0-alpha"
 dependencies = [
  "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "auto_enums 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "calculate 0.7.0 (git+https://gitlab.redox-os.org/redox-os/calc)",
  "criterion 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -321,6 +367,7 @@ dependencies = [
  "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "liner 0.4.5 (git+https://gitlab.redox-os.org/redox-os/liner)",
+ "object-pool 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "regex 1.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "serial_test 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -336,6 +383,7 @@ dependencies = [
 name = "ion_braces"
 version = "0.1.0"
 dependencies = [
+ "auto_enums 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "permutate 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "small 0.1.0 (git+https://gitlab.redox-os.org/redox-os/small)",
  "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -422,6 +470,15 @@ dependencies = [
  "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "lock_api"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "memchr"
 version = "2.2.0"
@@ -519,11 +576,48 @@ name = "numtoa"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "object-pool"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "ord_subset"
 version = "3.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "owning_ref"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "permutate"
 version = "0.3.2"
@@ -828,6 +922,11 @@ name = "smallvec"
 version = "0.6.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "stable_deref_trait"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "stackvector"
 version = "1.0.2"
@@ -1006,6 +1105,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
 "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
 "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
+"checksum auto_enums 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "5999c1e1bd0972da60a4a58d0eef0d183dab8b787a1fde0e94e9a995f6275928"
+"checksum auto_enums_core 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "76cde7b6c90dbc5499dc58777e4fd3af08124ac8c26778044c10934e41a1e26e"
+"checksum auto_enums_derive 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b14b1eac6d98375d2f325c86085dc75705fb27b95cce9a5ff232ee74d3813fa8"
 "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
 "checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
 "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
@@ -1026,6 +1128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum csv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f0782c7154d8dd08f4adeb5aa22ab178c10281915f7da68d10bb646f03aaee73"
 "checksum csv-core 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa5cdef62f37e6ffe7d1f07a381bc0db32b7a3ff1cac0de56cb0d81e71f53d65"
 "checksum decimal 2.0.4 (git+https://github.com/alkis/decimal.git)" = "<none>"
+"checksum derive_utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "58ced0880a3b675d62c255bbac6eefd4b4e672954084354cf65960ddea8be6d7"
 "checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
 "checksum err-derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3d8ff65eb6c2fc68e76557239d16f5698fd56603925b89856d3f0f7105fd4543"
 "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067"
@@ -1042,6 +1145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum lexical-core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e82e023e062f1d25f807ad182008fba1b46538e999f908a08cc0c29e084462e"
 "checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
 "checksum liner 0.4.5 (git+https://gitlab.redox-os.org/redox-os/liner)" = "<none>"
+"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
 "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
 "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
 "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
@@ -1054,7 +1158,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
 "checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba"
 "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef"
+"checksum object-pool 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "656d9629602722ed1e911c3654ca2f60869e828cd5be441ff8383c2341eac4bc"
 "checksum ord_subset 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7ce14664caf5b27f5656ff727defd68ae1eb75ef3c4d95259361df1eb376bef"
+"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
+"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337"
+"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9"
 "checksum permutate 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53b7d5b19a715ffab38693a9dd44b067fdfa2b18eef65bd93562dfe507022fae"
 "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
 "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
@@ -1092,6 +1200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum serial_test_derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "89dd85be2e2ad75b041c9df2892ac078fa6e0b90024028b2b9fb4125b7530f01"
 "checksum small 0.1.0 (git+https://gitlab.redox-os.org/redox-os/small)" = "<none>"
 "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be"
+"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
 "checksum stackvector 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c049c77bf85fbc036484c97b008276d539d9ebff9dfbde37b632ebcd5b8746b6"
 "checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5"
 "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
diff --git a/Cargo.toml b/Cargo.toml
index acd1a98072aaf3393e0638b35e41210942054524..573216cd3e956b6f08b843b076ca44395b0e1558 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -67,6 +67,8 @@ ion-ranges = { path = "members/ranges" }
 hashbrown = "0.1.2"
 itertools = "0.8"
 lexical = "2.0"
+object-pool = "0.3.1"
+auto_enums = "0.5.5"
 
 [lib]
 path = "src/lib/lib.rs"
diff --git a/members/braces/Cargo.toml b/members/braces/Cargo.toml
index 9a345265af703d470279f035e30c5fbc52410c2a..23d989320cc33b336eb049c8037890154eab94ac 100644
--- a/members/braces/Cargo.toml
+++ b/members/braces/Cargo.toml
@@ -2,8 +2,10 @@
 name = "ion_braces"
 version = "0.1.0"
 authors = ["Michael Murphy <mmstickman@gmail.com>"]
+edition = "2018"
 
 [dependencies]
 permutate = "0.3"
 smallvec = "0.6"
 small = { git = "https://gitlab.redox-os.org/redox-os/small", features = ["std"] }
+auto_enums = "0.5.5"
diff --git a/members/braces/src/lib.rs b/members/braces/src/lib.rs
index 0e0249f7a186aa627765155c6a229ec0fe5f32b4..9e97c0969bde2ff648674a687979468cc851892a 100644
--- a/members/braces/src/lib.rs
+++ b/members/braces/src/lib.rs
@@ -1,7 +1,4 @@
-extern crate permutate;
-extern crate small;
-extern crate smallvec;
-
+use auto_enums::auto_enum;
 use permutate::Permutator;
 use smallvec::SmallVec;
 
@@ -12,21 +9,16 @@ pub enum BraceToken {
     Expander,
 }
 
+#[auto_enum]
 pub fn expand<'a>(
     tokens: &'a [BraceToken],
     expanders: &'a [&'a [&'a str]],
-) -> Box<Iterator<Item = small::String> + 'a> {
+) -> impl Iterator<Item = small::String> + 'a {
+    #[auto_enum(Iterator)]
     match expanders.len() {
-        0 => Box::new(::std::iter::empty()),
-        1 => {
-            let single_brace_expand =
-                SingleBraceExpand { elements: expanders[0].iter().cloned(), tokens, loop_count: 0 };
-            Box::new(single_brace_expand)
-        }
-        _ => {
-            let multiple_brace_expand = MultipleBraceExpand::new(tokens, expanders);
-            Box::new(multiple_brace_expand)
-        }
+        0 => ::std::iter::empty(),
+        1 => SingleBraceExpand { elements: expanders[0].iter().cloned(), tokens, loop_count: 0 },
+        _ => MultipleBraceExpand::new(tokens, expanders),
     }
 }
 
diff --git a/src/lib/lib.rs b/src/lib/lib.rs
index f50e53b7e71c66cb6cc43c882d91e967322352aa..83b637515e65470f164a56cb799974f884b6b0fd 100644
--- a/src/lib/lib.rs
+++ b/src/lib/lib.rs
@@ -15,8 +15,10 @@ pub mod types;
 pub mod parser;
 mod ascii_helpers;
 mod builtins;
+mod memory;
 pub mod shell;
 
+pub(crate) use self::memory::IonPool;
 pub use crate::shell::{
     binary::MAN_ION, flags, pipe_exec::job_control::JobControl, status, Binary, Capture, Fork,
     IonError, IonResult, Shell, ShellBuilder,
diff --git a/src/lib/memory.rs b/src/lib/memory.rs
new file mode 100644
index 0000000000000000000000000000000000000000..ad932f565b550c5a998e0325b433d4e966f0f9c6
--- /dev/null
+++ b/src/lib/memory.rs
@@ -0,0 +1,36 @@
+// TODO: Shrink values that grow too large, after use.
+
+// use crate::types::Array;
+use object_pool::Pool;
+use small::String;
+
+thread_local! {
+    static STRINGS: Pool<String> = Pool::new(256, String::new);
+    // static STRING_VECS: Pool<Array> = Pool::new(1024, Array::new?);
+}
+
+pub struct IonPool;
+
+impl IonPool {
+    pub fn string<T, F: FnMut(&mut String) -> T>(mut callback: F) -> T {
+        STRINGS.with(|pool| match pool.pull() {
+            Some(ref mut string) => {
+                string.clear();
+                callback(string)
+            }
+            None => callback(&mut String::new()),
+        })
+    }
+
+    // pub fn vec_of_string<T, F: FnMut(&mut Array) -> T>(mut callback: F) -> T {
+    //     STRING_VECS.with(|pool| {
+    //         match pool.pull() {
+    //             Some(ref mut vector) => {
+    //                 vector.clear();
+    //                 callback(vector)
+    //             }
+    //             None => callback(&mut Array::new())
+    //         }
+    //     })
+    // }
+}
diff --git a/src/lib/parser/shell_expand/mod.rs b/src/lib/parser/shell_expand/mod.rs
index f5faa527ebb5b3cbd904204fbc9e58c0ca0a9f66..7b213599615d9e613116c744cbca32a5c4245a34 100644
--- a/src/lib/parser/shell_expand/mod.rs
+++ b/src/lib/parser/shell_expand/mod.rs
@@ -295,72 +295,95 @@ fn expand_braces<E: Expander>(
     let tokens: &mut Vec<BraceToken> = &mut Vec::new();
     let mut expanders: Vec<Vec<small::String>> = Vec::new();
 
-    for word in word_tokens {
-        match *word {
-            WordToken::Array(ref elements, ref index) => {
-                output.push_str(&array_expand(elements, expand_func, &index).join(" "));
-            }
-            WordToken::ArrayVariable(array, _, ref index) => {
-                if let Some(array) = expand_func.array(array, index) {
-                    output.push_str(&array.join(" "));
-                }
-            }
-            WordToken::ArrayProcess(command, _, ref index) => match *index {
-                Select::All => {
-                    let mut temp = small::String::new();
-                    expand_process(&mut temp, command, &Select::All, expand_func, false);
-                    output.push_str(&temp);
-                }
-                Select::Index(Index::Forward(id)) => {
-                    let mut temp = small::String::new();
-                    expand_process(&mut temp, command, &Select::All, expand_func, false);
-                    output.push_str(temp.split_whitespace().nth(id).unwrap_or_default());
-                }
-                Select::Index(Index::Backward(id)) => {
-                    let mut temp = small::String::new();
-                    expand_process(&mut temp, command, &Select::All, expand_func, false);
-                    output.push_str(temp.split_whitespace().rev().nth(id).unwrap_or_default());
-                }
-                Select::Range(range) => {
-                    let mut temp = small::String::new();
-                    expand_process(&mut temp, command, &Select::All, expand_func, false);
-                    let len = temp.split_whitespace().count();
-                    if let Some((start, length)) = range.bounds(len) {
-                        let res =
-                            temp.split_whitespace().skip(start).take(length).collect::<Vec<&str>>();
-                        output.push_str(&res.join(" "));
+    {
+        let output = &mut output;
+        crate::IonPool::string(|temp| {
+            for word in word_tokens {
+                match *word {
+                    WordToken::Array(ref elements, ref index) => {
+                        output.push_str(&array_expand(elements, expand_func, &index).join(" "));
+                    }
+                    WordToken::ArrayVariable(array, _, ref index) => {
+                        if let Some(array) = expand_func.array(array, index) {
+                            output.push_str(&array.join(" "));
+                        }
+                    }
+                    WordToken::ArrayProcess(command, _, ref index) => match *index {
+                        Select::All => {
+                            expand_process(temp, command, &Select::All, expand_func, false);
+                            output.push_str(&temp);
+                        }
+                        Select::Index(Index::Forward(id)) => {
+                            expand_process(temp, command, &Select::All, expand_func, false);
+                            output.push_str(temp.split_whitespace().nth(id).unwrap_or_default());
+                        }
+                        Select::Index(Index::Backward(id)) => {
+                            expand_process(temp, command, &Select::All, expand_func, false);
+                            output.push_str(
+                                temp.split_whitespace().rev().nth(id).unwrap_or_default(),
+                            );
+                        }
+                        Select::Range(range) => {
+                            expand_process(temp, command, &Select::All, expand_func, false);
+                            let len = temp.split_whitespace().count();
+                            if let Some((start, length)) = range.bounds(len) {
+                                let mut iter = temp.split_whitespace().skip(start).take(length);
+                                if let Some(str) = iter.next() {
+                                    output.push_str(str);
+                                    iter.for_each(|str| {
+                                        output.push(' ');
+                                        output.push_str(str);
+                                    });
+                                }
+                            }
+                        }
+                        Select::Key(_) | Select::None => (),
+                    },
+                    WordToken::ArrayMethod(ref method) => {
+                        method.handle(output, expand_func);
+                    }
+                    WordToken::StringMethod(ref method) => {
+                        method.handle(output, expand_func);
+                    }
+                    WordToken::Brace(ref nodes) => expand_brace(
+                        output,
+                        &mut expanders,
+                        tokens,
+                        nodes,
+                        expand_func,
+                        reverse_quoting,
+                    ),
+                    WordToken::Whitespace(whitespace) => output.push_str(whitespace),
+                    WordToken::Process(command, quoted, ref index) => {
+                        expand_process(
+                            output,
+                            command,
+                            &index,
+                            expand_func,
+                            quoted ^ reverse_quoting,
+                        );
+                    }
+                    WordToken::Variable(text, quoted, ref index) => {
+                        if let Some(expanded) = expand_func.string(text, quoted ^ reverse_quoting) {
+                            slice(output, expanded, &index);
+                        };
+                    }
+                    WordToken::Normal(ref text, _, tilde) => {
+                        expand(
+                            output,
+                            &mut expanded_words,
+                            expand_func,
+                            text.as_ref(),
+                            false,
+                            tilde,
+                        );
                     }
+                    WordToken::Arithmetic(s) => expand_arithmetic(output, s, expand_func),
                 }
-                Select::Key(_) | Select::None => (),
-            },
-            WordToken::ArrayMethod(ref method) => {
-                method.handle(&mut output, expand_func);
-            }
-            WordToken::StringMethod(ref method) => {
-                method.handle(&mut output, expand_func);
-            }
-            WordToken::Brace(ref nodes) => expand_brace(
-                &mut output,
-                &mut expanders,
-                tokens,
-                nodes,
-                expand_func,
-                reverse_quoting,
-            ),
-            WordToken::Whitespace(whitespace) => output.push_str(whitespace),
-            WordToken::Process(command, quoted, ref index) => {
-                expand_process(&mut output, command, &index, expand_func, quoted ^ reverse_quoting);
-            }
-            WordToken::Variable(text, quoted, ref index) => {
-                if let Some(expanded) = expand_func.string(text, quoted ^ reverse_quoting) {
-                    slice(&mut output, expanded, &index);
-                };
-            }
-            WordToken::Normal(ref text, _, tilde) => {
-                expand(&mut output, &mut expanded_words, expand_func, text.as_ref(), false, tilde);
+
+                temp.clear();
             }
-            WordToken::Arithmetic(s) => expand_arithmetic(&mut output, s, expand_func),
-        }
+        });
     }
 
     if expanders.is_empty() {
@@ -559,78 +582,87 @@ pub(crate) fn expand_tokens<E: Expander>(
         let mut output = small::String::new();
         let mut expanded_words = types::Array::new();
 
-        for word in token_buffer {
-            match *word {
-                WordToken::Array(ref elements, ref index) => {
-                    output.push_str(&array_expand(elements, expand_func, &index).join(" "));
-                }
-                WordToken::ArrayVariable(array, _, ref index) => {
-                    if let Some(array) = expand_func.array(array, index) {
-                        output.push_str(&array.join(" "));
-                    }
-                }
-                WordToken::ArrayProcess(command, _, ref index) => match index {
-                    Select::All => {
-                        let mut temp = small::String::new();
-                        expand_process(&mut temp, command, &Select::All, expand_func, false);
-                        output.push_str(&temp);
-                    }
-                    Select::Index(Index::Forward(id)) => {
-                        let mut temp = small::String::new();
-                        expand_process(&mut temp, command, &Select::All, expand_func, false);
-                        output.push_str(temp.split_whitespace().nth(*id).unwrap_or_default());
-                    }
-                    Select::Index(Index::Backward(id)) => {
-                        let mut temp = small::String::new();
-                        expand_process(&mut temp, command, &Select::All, expand_func, false);
-                        output.push_str(temp.split_whitespace().rev().nth(*id).unwrap_or_default());
-                    }
-                    Select::Range(range) => {
-                        let mut temp = small::String::new();
-                        expand_process(&mut temp, command, &Select::All, expand_func, false);
-                        if let Some((start, length)) = range.bounds(temp.split_whitespace().count())
-                        {
-                            let temp = temp
-                                .split_whitespace()
-                                .skip(start)
-                                .take(length)
-                                .collect::<Vec<_>>();
-                            output.push_str(&temp.join(" "))
+        {
+            let output = &mut output;
+            crate::IonPool::string(|temp| {
+                for word in token_buffer {
+                    match *word {
+                        WordToken::Array(ref elements, ref index) => {
+                            output.push_str(&array_expand(elements, expand_func, &index).join(" "));
                         }
+                        WordToken::ArrayVariable(array, _, ref index) => {
+                            if let Some(array) = expand_func.array(array, index) {
+                                output.push_str(&array.join(" "));
+                            }
+                        }
+                        WordToken::ArrayProcess(command, _, ref index) => match index {
+                            Select::All => {
+                                expand_process(temp, command, &Select::All, expand_func, false);
+                                output.push_str(&temp);
+                            }
+                            Select::Index(Index::Forward(id)) => {
+                                expand_process(temp, command, &Select::All, expand_func, false);
+                                output
+                                    .push_str(temp.split_whitespace().nth(*id).unwrap_or_default());
+                            }
+                            Select::Index(Index::Backward(id)) => {
+                                expand_process(temp, command, &Select::All, expand_func, false);
+                                output.push_str(
+                                    temp.split_whitespace().rev().nth(*id).unwrap_or_default(),
+                                );
+                            }
+                            Select::Range(range) => {
+                                expand_process(temp, command, &Select::All, expand_func, false);
+                                if let Some((start, length)) =
+                                    range.bounds(temp.split_whitespace().count())
+                                {
+                                    let temp = temp
+                                        .split_whitespace()
+                                        .skip(start)
+                                        .take(length)
+                                        .collect::<Vec<_>>();
+                                    output.push_str(&temp.join(" "))
+                                }
+                            }
+                            Select::Key(_) | Select::None => (),
+                        },
+                        WordToken::ArrayMethod(ref method) => {
+                            method.handle(output, expand_func);
+                        }
+                        WordToken::StringMethod(ref method) => {
+                            method.handle(output, expand_func);
+                        }
+                        WordToken::Brace(_) => unreachable!(),
+                        WordToken::Normal(ref text, do_glob, tilde) => {
+                            expand(
+                                output,
+                                &mut expanded_words,
+                                expand_func,
+                                text.as_ref(),
+                                do_glob,
+                                tilde,
+                            );
+                        }
+                        WordToken::Whitespace(text) => {
+                            output.push_str(text);
+                        }
+                        WordToken::Process(command, quoted, ref index) => {
+                            let quoted = if reverse_quoting { !quoted } else { quoted };
+                            expand_process(output, command, &index, expand_func, quoted);
+                        }
+                        WordToken::Variable(text, quoted, ref index) => {
+                            if let Some(expanded) =
+                                expand_func.string(text, quoted ^ reverse_quoting)
+                            {
+                                slice(output, expanded, &index);
+                            }
+                        }
+                        WordToken::Arithmetic(s) => expand_arithmetic(output, s, expand_func),
                     }
-                    Select::Key(_) | Select::None => (),
-                },
-                WordToken::ArrayMethod(ref method) => {
-                    method.handle(&mut output, expand_func);
-                }
-                WordToken::StringMethod(ref method) => {
-                    method.handle(&mut output, expand_func);
-                }
-                WordToken::Brace(_) => unreachable!(),
-                WordToken::Normal(ref text, do_glob, tilde) => {
-                    expand(
-                        &mut output,
-                        &mut expanded_words,
-                        expand_func,
-                        text.as_ref(),
-                        do_glob,
-                        tilde,
-                    );
-                }
-                WordToken::Whitespace(text) => {
-                    output.push_str(text);
-                }
-                WordToken::Process(command, quoted, ref index) => {
-                    let quoted = if reverse_quoting { !quoted } else { quoted };
-                    expand_process(&mut output, command, &index, expand_func, quoted);
-                }
-                WordToken::Variable(text, quoted, ref index) => {
-                    if let Some(expanded) = expand_func.string(text, quoted ^ reverse_quoting) {
-                        slice(&mut output, expanded, &index);
-                    }
+
+                    temp.clear();
                 }
-                WordToken::Arithmetic(s) => expand_arithmetic(&mut output, s, expand_func),
-            }
+            });
         }
 
         if !output.is_empty() {
@@ -648,33 +680,36 @@ pub(crate) fn expand_tokens<E: Expander>(
 /// ```
 /// if `x=5` and `y=7`
 fn expand_arithmetic<E: Expander>(output: &mut small::String, input: &str, expander: &E) {
-    // small::String cannot be created with a capacity of 0 without causing a panic
-    let len = if !input.is_empty() { input.len() } else { 1 };
-    let mut intermediate = small::String::with_capacity(len);
-    let mut varbuf = small::String::new();
-    let flush = |var: &mut small::String, out: &mut small::String| {
-        if !var.is_empty() {
-            // We have reached the end of a potential variable, so we expand it and push
-            // it onto the result
-            out.push_str(expander.string(&var, false).as_ref().unwrap_or(var));
-        }
-    };
-    for c in input.bytes() {
-        match c {
-            48...57 | 65...90 | 95 | 97...122 => {
-                varbuf.push(c as char);
-            }
-            _ => {
-                flush(&mut varbuf, &mut intermediate);
-                varbuf.clear();
-                intermediate.push(c as char);
+    crate::IonPool::string(|intermediate| {
+        crate::IonPool::string(|varbuf| {
+            let flush = |var: &mut small::String, out: &mut small::String| {
+                if !var.is_empty() {
+                    // We have reached the end of a potential variable, so we expand it and push
+                    // it onto the result
+                    out.push_str(expander.string(&var, false).as_ref().unwrap_or(var));
+                }
+            };
+
+            for c in input.bytes() {
+                match c {
+                    48...57 | 65...90 | 95 | 97...122 => {
+                        varbuf.push(c as char);
+                    }
+                    _ => {
+                        flush(varbuf, intermediate);
+                        varbuf.clear();
+                        intermediate.push(c as char);
+                    }
+                }
             }
-        }
-    }
-    flush(&mut varbuf, &mut intermediate);
-    output.push_str(&match calc::eval(&intermediate) {
-        Ok(s) => s.to_string(),
-        Err(e) => e.to_string(),
+
+            flush(varbuf, intermediate);
+
+            output.push_str(&match calc::eval(&intermediate) {
+                Ok(s) => s.to_string(),
+                Err(e) => e.to_string(),
+            });
+        });
     });
 }
 
diff --git a/src/lib/shell/completer.rs b/src/lib/shell/completer.rs
index 2c4ddf5f388e8050f26d824058f0b98acf0ea645..8c1e9567df91592ebbe06149cc4fb931e06979d5 100644
--- a/src/lib/shell/completer.rs
+++ b/src/lib/shell/completer.rs
@@ -3,6 +3,7 @@ use super::{
     escape::{escape, unescape},
     variables::Variables,
 };
+use auto_enums::auto_enum;
 use glob::glob;
 use liner::{Completer, FilenameCompleter};
 use smallvec::SmallVec;
@@ -86,6 +87,7 @@ impl Completer for IonFileCompleter {
     }
 }
 
+#[auto_enum]
 fn filename_completion<'a, LC>(
     start: &'a str,
     liner_complete: LC,
@@ -131,9 +133,10 @@ where
         }
     });
 
-    let iter_inner_glob: Box<Iterator<Item = String>> = match globs {
-        Some(iter) => Box::new(iter),
-        None => Box::new(iter::once(escape(start))),
+    #[auto_enum(Iterator)]
+    let iter_inner_glob = match globs {
+        Some(iter) => iter,
+        None => iter::once(escape(start)),
     };
 
     // Use Liner::Completer as well, to preserve the previous behaviour
diff --git a/src/lib/shell/pipe_exec/mod.rs b/src/lib/shell/pipe_exec/mod.rs
index 060c143f804d0b4513364110d3df734686ce772a..cc61d94e2b953fa5b1cbbd45a157241fd15bccea 100644
--- a/src/lib/shell/pipe_exec/mod.rs
+++ b/src/lib/shell/pipe_exec/mod.rs
@@ -582,15 +582,21 @@ impl PipelineExecution for Shell {
     }
 
     fn wait(&mut self, pgid: u32, commands: SmallVec<[RefinedJob; 16]>) -> i32 {
-        let as_string = if commands.is_empty() {
-            // This doesn't allocate
-            String::new()
-        } else {
-            commands.iter().map(RefinedJob::long).collect::<Vec<String>>().join(" | ")
-        };
+        crate::IonPool::string(|as_string| {
+            if !commands.is_empty() {
+                let mut iter = commands.iter().map(RefinedJob::long);
+                if let Some(str) = iter.next() {
+                    as_string.push_str(&str);
+                    iter.for_each(|str| {
+                        as_string.push_str(" | ");
+                        as_string.push_str(&str);
+                    })
+                }
+            }
 
-        // Watch the foreground group, dropping all commands that exit as they exit.
-        self.watch_foreground(-(pgid as i32), &as_string)
+            // Watch the foreground group, dropping all commands that exit as they exit.
+            self.watch_foreground(-(pgid as i32), &as_string)
+        })
     }
 
     fn generate_commands(